summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2016-12-17 23:38:33 +0000
committerpatrick <patrick@openbsd.org>2016-12-17 23:38:33 +0000
commitf24071e5a82bde237999ed17cfea827c436463e8 (patch)
treee8624b507581722d2d79bb0e61ae37b1c6b4b4bf
parentsync (diff)
downloadwireguard-openbsd-f24071e5a82bde237999ed17cfea827c436463e8.tar.xz
wireguard-openbsd-f24071e5a82bde237999ed17cfea827c436463e8.zip
Import of OpenBSD/arm64
This commit contains all the kernel files related to the OpenBSD/arm64 port. It is based on the PowerPC pmap, loongson, arm/armv7 code and FreeBSD aarch64 code. Hard work done by Dale Rahn.
-rw-r--r--sys/arch/arm64/Makefile45
-rw-r--r--sys/arch/arm64/arm64/arm64_a4x_iobus.c135
-rw-r--r--sys/arch/arm64/arm64/arm64_iobus.c198
-rw-r--r--sys/arch/arm64/arm64/arm64_machdep.h27
-rw-r--r--sys/arch/arm64/arm64/arm64_mutex.c119
-rw-r--r--sys/arch/arm64/arm64/arm64var.h26
-rw-r--r--sys/arch/arm64/arm64/ast.c45
-rw-r--r--sys/arch/arm64/arm64/autoconf.c89
-rw-r--r--sys/arch/arm64/arm64/bus_dma.c713
-rw-r--r--sys/arch/arm64/arm64/conf.c387
-rw-r--r--sys/arch/arm64/arm64/copy.S120
-rw-r--r--sys/arch/arm64/arm64/copystr.S93
-rw-r--r--sys/arch/arm64/arm64/cpuswitch.S104
-rw-r--r--sys/arch/arm64/arm64/db_disasm.c29
-rw-r--r--sys/arch/arm64/arm64/db_interface.c372
-rw-r--r--sys/arch/arm64/arm64/db_trace.c96
-rw-r--r--sys/arch/arm64/arm64/disksubr.c137
-rw-r--r--sys/arch/arm64/arm64/exception.S214
-rw-r--r--sys/arch/arm64/arm64/genassym.cf93
-rw-r--r--sys/arch/arm64/arm64/intr.c629
-rw-r--r--sys/arch/arm64/arm64/locore.S652
-rw-r--r--sys/arch/arm64/arm64/machdep.c1106
-rw-r--r--sys/arch/arm64/arm64/mem.c270
-rw-r--r--sys/arch/arm64/arm64/pmap.c2397
-rw-r--r--sys/arch/arm64/arm64/process_machdep.c93
-rw-r--r--sys/arch/arm64/arm64/sig_machdep.c217
-rw-r--r--sys/arch/arm64/arm64/softintr.c196
-rw-r--r--sys/arch/arm64/arm64/support.S255
-rw-r--r--sys/arch/arm64/arm64/sys_machdep.c71
-rw-r--r--sys/arch/arm64/arm64/syscall.c134
-rw-r--r--sys/arch/arm64/arm64/trap.c334
-rw-r--r--sys/arch/arm64/arm64/vfp.c284
-rw-r--r--sys/arch/arm64/arm64/vm_machdep.c183
-rw-r--r--sys/arch/arm64/compile/GENERIC/Makefile1
-rw-r--r--sys/arch/arm64/compile/Makefile7
-rw-r--r--sys/arch/arm64/compile/Makefile.inc18
-rw-r--r--sys/arch/arm64/compile/RAMDISK/Makefile1
-rw-r--r--sys/arch/arm64/conf/GENERIC58
-rw-r--r--sys/arch/arm64/conf/Makefile.arm64196
-rw-r--r--sys/arch/arm64/conf/files.arm64106
-rw-r--r--sys/arch/arm64/conf/kern.ldscript81
-rw-r--r--sys/arch/arm64/dev/agtimer.c392
-rw-r--r--sys/arch/arm64/dev/ampintc.c607
-rw-r--r--sys/arch/arm64/dev/arm64_bus_space.c312
-rw-r--r--sys/arch/arm64/dev/com_fdt.c196
-rw-r--r--sys/arch/arm64/dev/mainbus.c216
-rw-r--r--sys/arch/arm64/dev/mainbus.h29
-rw-r--r--sys/arch/arm64/dev/pluart.c901
-rw-r--r--sys/arch/arm64/dev/simplebus.c242
-rw-r--r--sys/arch/arm64/dev/simplebusvar.h33
-rw-r--r--sys/arch/arm64/dev/virtio_mmio.c454
-rw-r--r--sys/arch/arm64/include/_float.h96
-rw-r--r--sys/arch/arm64/include/_types.h144
-rw-r--r--sys/arch/arm64/include/apmvar.h121
-rw-r--r--sys/arch/arm64/include/armreg.h248
-rw-r--r--sys/arch/arm64/include/asm.h146
-rw-r--r--sys/arch/arm64/include/atomic.h39
-rw-r--r--sys/arch/arm64/include/bootconfig.h58
-rw-r--r--sys/arch/arm64/include/bus.h530
-rw-r--r--sys/arch/arm64/include/cdefs.h16
-rw-r--r--sys/arch/arm64/include/conf.h82
-rw-r--r--sys/arch/arm64/include/cpu.h264
-rw-r--r--sys/arch/arm64/include/db_machdep.h92
-rw-r--r--sys/arch/arm64/include/disklabel.h25
-rw-r--r--sys/arch/arm64/include/endian.h37
-rw-r--r--sys/arch/arm64/include/exec.h32
-rw-r--r--sys/arch/arm64/include/fdt.h37
-rw-r--r--sys/arch/arm64/include/fenv.h120
-rw-r--r--sys/arch/arm64/include/float.h97
-rw-r--r--sys/arch/arm64/include/frame.h74
-rw-r--r--sys/arch/arm64/include/hypervisor.h86
-rw-r--r--sys/arch/arm64/include/ieee.h149
-rw-r--r--sys/arch/arm64/include/ieeefp.h41
-rw-r--r--sys/arch/arm64/include/internal_types.h10
-rw-r--r--sys/arch/arm64/include/intr.h190
-rw-r--r--sys/arch/arm64/include/kcore.h15
-rw-r--r--sys/arch/arm64/include/limits.h56
-rw-r--r--sys/arch/arm64/include/loadfile_machdep.h53
-rw-r--r--sys/arch/arm64/include/lock.h32
-rw-r--r--sys/arch/arm64/include/machdep.h27
-rw-r--r--sys/arch/arm64/include/machine_reg.h57
-rw-r--r--sys/arch/arm64/include/mplock.h53
-rw-r--r--sys/arch/arm64/include/mutex.h67
-rw-r--r--sys/arch/arm64/include/param.h84
-rw-r--r--sys/arch/arm64/include/pcb.h45
-rw-r--r--sys/arch/arm64/include/pmap.h138
-rw-r--r--sys/arch/arm64/include/proc.h47
-rw-r--r--sys/arch/arm64/include/profile.h68
-rw-r--r--sys/arch/arm64/include/pte.h130
-rw-r--r--sys/arch/arm64/include/ptrace.h22
-rw-r--r--sys/arch/arm64/include/reg.h35
-rw-r--r--sys/arch/arm64/include/reloc.h126
-rw-r--r--sys/arch/arm64/include/setjmp.h83
-rw-r--r--sys/arch/arm64/include/signal.h71
-rw-r--r--sys/arch/arm64/include/softintr.h100
-rw-r--r--sys/arch/arm64/include/spinlock.h29
-rw-r--r--sys/arch/arm64/include/stdarg.h56
-rw-r--r--sys/arch/arm64/include/swi.h23
-rw-r--r--sys/arch/arm64/include/sysarch.h21
-rw-r--r--sys/arch/arm64/include/tcb.h60
-rw-r--r--sys/arch/arm64/include/trap.h22
-rw-r--r--sys/arch/arm64/include/vfp.h47
-rw-r--r--sys/arch/arm64/include/vmparam.h112
-rw-r--r--sys/arch/arm64/stand/Makefile5
-rw-r--r--sys/arch/arm64/stand/efiboot/Makefile78
-rw-r--r--sys/arch/arm64/stand/efiboot/conf.c56
-rw-r--r--sys/arch/arm64/stand/efiboot/disk.h20
-rw-r--r--sys/arch/arm64/stand/efiboot/efiboot.c527
-rw-r--r--sys/arch/arm64/stand/efiboot/efiboot.h25
-rw-r--r--sys/arch/arm64/stand/efiboot/eficall.h53
-rw-r--r--sys/arch/arm64/stand/efiboot/efidev.c229
-rw-r--r--sys/arch/arm64/stand/efiboot/efidev.h35
-rw-r--r--sys/arch/arm64/stand/efiboot/exec.c87
-rw-r--r--sys/arch/arm64/stand/efiboot/fdt.c574
-rw-r--r--sys/arch/arm64/stand/efiboot/fdt.h68
-rw-r--r--sys/arch/arm64/stand/efiboot/heap.h29
-rw-r--r--sys/arch/arm64/stand/efiboot/ldscript.arm6485
-rw-r--r--sys/arch/arm64/stand/efiboot/libsa.h30
-rw-r--r--sys/arch/arm64/stand/efiboot/self_reloc.c122
-rw-r--r--sys/arch/arm64/stand/efiboot/start.S166
120 files changed, 20315 insertions, 0 deletions
diff --git a/sys/arch/arm64/Makefile b/sys/arch/arm64/Makefile
new file mode 100644
index 00000000000..946d2c82abc
--- /dev/null
+++ b/sys/arch/arm64/Makefile
@@ -0,0 +1,45 @@
+# $OpenBSD: Makefile,v 1.1 2016/12/17 23:38:33 patrick Exp $
+
+S= ${.CURDIR}/../..
+KFILE= GENERIC
+.if exists(conf/GENERIC.MP)
+KFILE= GENERIC.MP
+.endif
+TDIRS= ${_arch} include
+TAGS= ${.CURDIR}/tags
+
+NOPROG=
+NOMAN=
+NOOBJ=
+SUBDIR= stand compile
+
+# config the fattest kernel we can find into a temporary dir
+# to create a Makefile. Then use make to pull some variables
+# out and push them into the sub-shell to expand the paths,
+# and finally run ctags.
+tags::
+ TDIR=`mktemp -d /tmp/_tagXXXXXXXXXX` || exit 1; \
+ eval "S=${S}" && \
+ config -s ${S} -b $${TDIR} ${.CURDIR}/conf/${KFILE} && \
+ eval "_arch=\"`make -V _arch -f $${TDIR}/Makefile`\"" && \
+ eval "_mach=\"`make -V _mach -f $${TDIR}/Makefile`\"" && \
+ eval "_machdir=\$S/arch/$${_mach}" && \
+ eval "_archdir=\$S/arch/$${_arch}" && \
+ eval "HFILES=\"`find $S \( -path $S/'arch' -o -path $S/stand -o -path $S/lib/libsa -o -path $S'/lib/libkern/arch' \) -prune -o -name '*.h'; find $${_machdir} $${_archdir} $S/lib/libkern/arch/$${_mach} \( -name boot -o -name stand \) -prune -o -name '*.h'`\"" && \
+ eval "SFILES=\"`make -V SFILES -f $${TDIR}/Makefile`\"" && \
+ eval "CFILES=\"`make -V CFILES -f $${TDIR}/Makefile`\"" && \
+ eval "AFILES=\"`make -V AFILES -f $${TDIR}/Makefile`\"" && \
+ ctags -wd -f ${TAGS} $${CFILES} $${HFILES} && \
+ egrep "^[_A-Z]*ENTRY[_A-Z]*\(.*\)" $${SFILES} $${AFILES} | \
+ sed "s;\\([^:]*\\):\\([^(]*\\)(\\([^, )]*\\)\\(.*\\);\\3 \\1 /^\\2(\\3\\4$$/;" \
+ >> ${TAGS} && \
+ sort -o ${TAGS} ${TAGS} && \
+ rm -rf $${TDIR}
+
+links:
+ -for i in conf ${TDIRS}; do \
+ (cd $$i && rm -f tags; ln -s tags tags); done
+
+obj: _SUBDIRUSE
+
+.include <bsd.prog.mk>
diff --git a/sys/arch/arm64/arm64/arm64_a4x_iobus.c b/sys/arch/arm64/arm64/arm64_a4x_iobus.c
new file mode 100644
index 00000000000..8038b17bad2
--- /dev/null
+++ b/sys/arch/arm64/arm64/arm64_a4x_iobus.c
@@ -0,0 +1,135 @@
+/* $OpenBSD: arm64_a4x_iobus.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
+ *
+ * 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 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.
+ *
+ */
+
+/*
+ * This is a iobus driver.
+ * It handles configuration of all devices on the processor bus except UART.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/atomic.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <uvm/uvm_extern.h>
+#include <machine/pmap.h>
+
+#if 0
+u_int8_t iobus_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int16_t iobus_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int32_t iobus_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int64_t iobus_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+
+void iobus_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int8_t);
+void iobus_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int16_t);
+void iobus_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int32_t);
+void iobus_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int64_t);
+
+void iobus_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ u_int8_t *, bus_size_t);
+void iobus_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const u_int8_t *, bus_size_t);
+void iobus_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ u_int8_t *, bus_size_t);
+void iobus_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const u_int8_t *, bus_size_t);
+void iobus_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ u_int8_t *, bus_size_t);
+void iobus_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const u_int8_t *, bus_size_t);
+
+struct cfattach iobus_ca = {
+ sizeof(struct device), iobusmatch, iobusattach
+};
+
+struct cfdriver iobus_cd = {
+ NULL, "iobus", DV_DULL
+};
+#endif
+
+int iobus_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
+ int flags, bus_space_handle_t *bshp);
+void iobus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t size);
+
+bus_space_t arm64_bs_tag = {
+ .bus_base = 0ULL, // XXX
+ .bus_private = NULL,
+ ._space_read_1 = generic_space_read_1,
+ ._space_write_1 = generic_space_write_1,
+ ._space_read_2 = generic_space_read_2,
+ ._space_write_2 = generic_space_write_2,
+ ._space_read_4 = generic_space_read_4,
+ ._space_write_4 = generic_space_write_4,
+ ._space_read_8 = generic_space_read_8,
+ ._space_write_8 = generic_space_write_8,
+ ._space_read_raw_2 = generic_space_read_raw_2,
+ ._space_write_raw_2 = generic_space_write_raw_2,
+ ._space_read_raw_4 = generic_space_read_raw_4,
+ ._space_write_raw_4 = generic_space_write_raw_4,
+ ._space_read_raw_8 = generic_space_read_raw_8,
+ ._space_write_raw_8 = generic_space_write_raw_8,
+ ._space_map = iobus_space_map,
+ ._space_unmap = iobus_space_unmap,
+ ._space_subregion = generic_space_region,
+ ._space_vaddr = generic_space_vaddr
+};
+
+bus_space_handle_t iobus_h;
+
+#if 0
+struct machine_bus_dma_tag iobus_bus_dma_tag = {
+ NULL, /* _cookie */
+ _dmamap_create,
+ _dmamap_destroy,
+ _dmamap_load,
+ _dmamap_load_mbuf,
+ _dmamap_load_uio,
+ _dmamap_load_raw,
+ _dmamap_load_buffer,
+ _dmamap_unload,
+ _dmamap_sync,
+ _dmamem_alloc,
+ _dmamem_free,
+ _dmamem_map,
+ _dmamem_unmap,
+ _dmamem_mmap,
+ iobus_pa_to_device,
+ iobus_device_to_pa,
+ 0
+};
+#endif
diff --git a/sys/arch/arm64/arm64/arm64_iobus.c b/sys/arch/arm64/arm64/arm64_iobus.c
new file mode 100644
index 00000000000..5f9ad2a808c
--- /dev/null
+++ b/sys/arch/arm64/arm64/arm64_iobus.c
@@ -0,0 +1,198 @@
+/* $OpenBSD: arm64_iobus.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se)
+ *
+ * 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 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.
+ *
+ */
+
+/*
+ * This is a iobus driver.
+ * It handles configuration of all devices on the processor bus except UART.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/atomic.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <uvm/uvm_extern.h>
+#include <machine/pmap.h>
+
+#if 0
+u_int8_t iobus_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int16_t iobus_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int32_t iobus_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+u_int64_t iobus_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+
+void iobus_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int8_t);
+void iobus_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int16_t);
+void iobus_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int32_t);
+void iobus_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ u_int64_t);
+
+void iobus_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ u_int8_t *, bus_size_t);
+void iobus_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const u_int8_t *, bus_size_t);
+void iobus_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ u_int8_t *, bus_size_t);
+void iobus_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const u_int8_t *, bus_size_t);
+void iobus_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ u_int8_t *, bus_size_t);
+void iobus_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
+ const u_int8_t *, bus_size_t);
+
+struct cfattach iobus_ca = {
+ sizeof(struct device), iobusmatch, iobusattach
+};
+
+struct cfdriver iobus_cd = {
+ NULL, "iobus", DV_DULL
+};
+#endif
+
+int iobus_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
+ int flags, bus_space_handle_t *bshp);
+void iobus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t size);
+
+bus_space_t arm64_bs_tag = {
+ .bus_base = 0ULL, // XXX
+ .bus_private = NULL,
+ ._space_read_1 = generic_space_read_1,
+ ._space_write_1 = generic_space_write_1,
+ ._space_read_2 = generic_space_read_2,
+ ._space_write_2 = generic_space_write_2,
+ ._space_read_4 = generic_space_read_4,
+ ._space_write_4 = generic_space_write_4,
+ ._space_read_8 = generic_space_read_8,
+ ._space_write_8 = generic_space_write_8,
+ ._space_read_raw_2 = generic_space_read_raw_2,
+ ._space_write_raw_2 = generic_space_write_raw_2,
+ ._space_read_raw_4 = generic_space_read_raw_4,
+ ._space_write_raw_4 = generic_space_write_raw_4,
+ ._space_read_raw_8 = generic_space_read_raw_8,
+ ._space_write_raw_8 = generic_space_write_raw_8,
+ ._space_map = iobus_space_map,
+ ._space_unmap = iobus_space_unmap,
+ ._space_subregion = generic_space_region,
+ ._space_vaddr = generic_space_vaddr
+};
+
+bus_space_handle_t iobus_h;
+
+#if 0
+struct machine_bus_dma_tag iobus_bus_dma_tag = {
+ NULL, /* _cookie */
+ _dmamap_create,
+ _dmamap_destroy,
+ _dmamap_load,
+ _dmamap_load_mbuf,
+ _dmamap_load_uio,
+ _dmamap_load_raw,
+ _dmamap_load_buffer,
+ _dmamap_unload,
+ _dmamap_sync,
+ _dmamem_alloc,
+ _dmamem_free,
+ _dmamem_map,
+ _dmamem_unmap,
+ _dmamem_mmap,
+ iobus_pa_to_device,
+ iobus_device_to_pa,
+ 0
+};
+#endif
+
+int
+iobus_space_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ u_long startpa, endpa, pa;
+ vaddr_t va;
+ int cache = flags & BUS_SPACE_MAP_CACHEABLE ?
+ PMAP_CACHE_WB : PMAP_CACHE_CI;
+
+ startpa = trunc_page(bpa);
+ endpa = round_page(bpa + size);
+
+ va = (vaddr_t)km_alloc(endpa - startpa, &kv_any, &kp_none, &kd_nowait);
+ if (! va)
+ return(ENOMEM);
+
+ *bshp = (bus_space_handle_t)(va + (bpa - startpa));
+
+ for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
+ pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, cache);
+ }
+ pmap_update(pmap_kernel());
+
+ return(0);
+}
+
+void
+iobus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
+{
+ vaddr_t va, endva;
+
+ va = trunc_page((vaddr_t)bsh);
+ endva = round_page((vaddr_t)bsh + size);
+
+ pmap_kremove(va, endva - va);
+ pmap_update(pmap_kernel());
+ km_free((void *)va, endva - va, &kv_any, &kp_none);
+}
+
+bus_space_t arm64_a4x_bs_tag = {
+ .bus_base = 0ULL, // XXX
+ .bus_private = NULL,
+ ._space_read_1 = a4x_space_read_1,
+ ._space_write_1 = a4x_space_write_1,
+ ._space_read_2 = a4x_space_read_2,
+ ._space_write_2 = a4x_space_write_2,
+ ._space_read_4 = a4x_space_read_4,
+ ._space_write_4 = a4x_space_write_4,
+ ._space_read_8 = a4x_space_read_8,
+ ._space_write_8 = a4x_space_write_8,
+ ._space_read_raw_2 = a4x_space_read_raw_2,
+ ._space_write_raw_2 = a4x_space_write_raw_2,
+ ._space_read_raw_4 = a4x_space_read_raw_4,
+ ._space_write_raw_4 = a4x_space_write_raw_4,
+ ._space_read_raw_8 = a4x_space_read_raw_8,
+ ._space_write_raw_8 = a4x_space_write_raw_8,
+ ._space_map = iobus_space_map,
+ ._space_unmap = iobus_space_unmap,
+ ._space_subregion = generic_space_region,
+ ._space_vaddr = generic_space_vaddr
+};
+
diff --git a/sys/arch/arm64/arm64/arm64_machdep.h b/sys/arch/arm64/arm64/arm64_machdep.h
new file mode 100644
index 00000000000..6f8666f3fca
--- /dev/null
+++ b/sys/arch/arm64/arm64/arm64_machdep.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: arm64_machdep.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef __ARM64_MACHDEP_H__
+#define __ARM64_MACHDEP_H__
+
+extern int stdout_node;
+
+void *fdt_find_cons(const char *);
+extern void (*cpuresetfn)(void);
+extern void (*powerdownfn)(void);
+
+#endif /* __ARM64_MACHDEP_H__ */
diff --git a/sys/arch/arm64/arm64/arm64_mutex.c b/sys/arch/arm64/arm64/arm64_mutex.c
new file mode 100644
index 00000000000..95d27ee7673
--- /dev/null
+++ b/sys/arch/arm64/arm64/arm64_mutex.c
@@ -0,0 +1,119 @@
+/* $OpenBSD: arm64_mutex.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2004 Artur Grabowski <art@openbsd.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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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/mutex.h>
+#include <sys/systm.h>
+#include <sys/atomic.h>
+
+#include <machine/intr.h>
+
+#include <ddb/db_output.h>
+
+void
+__mtx_init(struct mutex *mtx, int wantipl)
+{
+ mtx->mtx_owner = NULL;
+ mtx->mtx_wantipl = wantipl;
+ mtx->mtx_oldipl = IPL_NONE;
+}
+
+#ifdef MP_LOCKDEBUG
+#ifndef DDB
+#error "MP_LOCKDEBUG requires DDB"
+#endif
+
+/* CPU-dependent timing, needs this to be settable from ddb. */
+extern int __mp_lock_spinout;
+#endif
+
+void
+mtx_enter(struct mutex *mtx)
+{
+#ifdef MP_LOCKDEBUG
+ int ticks = __mp_lock_spinout;
+#endif
+
+ while (mtx_enter_try(mtx) == 0) {
+#ifdef MP_LOCKDEBUG
+ if (--ticks == 0) {
+ db_printf("%s(%p): lock spun out", __func__, mtx);
+ Debugger();
+ ticks = __mp_lock_spinout;
+ }
+#endif
+ }
+}
+
+int
+mtx_enter_try(struct mutex *mtx)
+{
+ struct cpu_info *owner, *ci = curcpu();
+ int s;
+
+ if (mtx->mtx_wantipl != IPL_NONE)
+ s = splraise(mtx->mtx_wantipl);
+
+ owner = atomic_cas_ptr(&mtx->mtx_owner, NULL, ci);
+#ifdef DIAGNOSTIC
+ if (__predict_false(owner == ci))
+ panic("mtx %p: locking against myself", mtx);
+#endif
+ if (owner == NULL) {
+ membar_enter();
+ if (mtx->mtx_wantipl != IPL_NONE)
+ mtx->mtx_oldipl = s;
+#ifdef DIAGNOSTIC
+ ci->ci_mutex_level++;
+#endif
+ return (1);
+ }
+
+ if (mtx->mtx_wantipl != IPL_NONE)
+ splx(s);
+
+ return (0);
+}
+
+void
+mtx_leave(struct mutex *mtx)
+{
+ int s;
+
+ MUTEX_ASSERT_LOCKED(mtx);
+
+#ifdef DIAGNOSTIC
+ curcpu()->ci_mutex_level--;
+#endif
+
+ s = mtx->mtx_oldipl;
+#ifdef MULTIPROCESSOR
+ membar_exit();
+#endif
+ mtx->mtx_owner = NULL;
+ if (mtx->mtx_wantipl != IPL_NONE)
+ splx(s);
+}
diff --git a/sys/arch/arm64/arm64/arm64var.h b/sys/arch/arm64/arm64/arm64var.h
new file mode 100644
index 00000000000..dc6374e5efb
--- /dev/null
+++ b/sys/arch/arm64/arm64/arm64var.h
@@ -0,0 +1,26 @@
+/* $OpenBSD: arm64var.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com>
+ * Copyright (c) 2012-2013 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.
+ */
+
+#ifndef __ARM64VAR_H__
+#define __ARM64VAR_H__
+
+extern bus_space_t arm64_bs_tag;
+extern bus_space_t arm64_a4x_bs_tag;
+
+#endif /* __ARM64VAR_H__ */
+
diff --git a/sys/arch/arm64/arm64/ast.c b/sys/arch/arm64/arm64/ast.c
new file mode 100644
index 00000000000..171eb3a06c9
--- /dev/null
+++ b/sys/arch/arm64/arm64/ast.c
@@ -0,0 +1,45 @@
+/* $OpenBSD: ast.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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/types.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/syscall.h>
+#include <sys/syscall_mi.h>
+#include <machine/pcb.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/frame.h>
+
+/*
+ * Transform cpu ast to mi_ast
+ */
+
+void
+ast(struct trapframe *tf)
+{
+ struct proc *p = curcpu()->ci_curproc;
+ int want_resched = curcpu()->ci_want_resched;
+
+ uvmexp.softs++;
+ mi_ast(p, want_resched);
+ userret(p);
+}
diff --git a/sys/arch/arm64/arm64/autoconf.c b/sys/arch/arm64/arm64/autoconf.c
new file mode 100644
index 00000000000..cd2c21c1508
--- /dev/null
+++ b/sys/arch/arm64/arm64/autoconf.c
@@ -0,0 +1,89 @@
+/* $OpenBSD: autoconf.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2009 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/reboot.h>
+#include <sys/hibernate.h>
+
+#include <machine/bootconfig.h>
+
+extern void dumpconf(void);
+void parsepmonbp(void);
+
+struct device *bootdv = NULL;
+enum devclass bootdev_class = DV_DULL;
+
+void
+cpu_configure(void)
+{
+ (void)splhigh();
+
+ softintr_init();
+ (void)config_rootfound("mainbus", NULL);
+
+ cold = 0;
+}
+
+void
+diskconf(void)
+{
+ size_t len;
+ char *p;
+ dev_t tmpdev;
+
+ if (*boot_file != '\0')
+ printf("bootfile: %s\n", boot_file);
+
+ if (bootdv == NULL) {
+
+ // boot_file is of the format <device>:/bsd we want the device part
+ if ((p = strchr(boot_file, ':')) != NULL)
+ len = p - boot_file;
+ else
+ len = strlen(boot_file);
+ bootdv = parsedisk(boot_file, len, 0, &tmpdev);
+ }
+
+ if (bootdv != NULL)
+ printf("boot device: %s\n", bootdv->dv_xname);
+ else
+ printf("boot device: lookup %s failed \n", boot_file);
+
+ setroot(bootdv, 0, RB_USERREQ);
+ dumpconf();
+
+#ifdef HIBERNATE
+ hibernate_resume();
+#endif /* HIBERNATE */
+}
+
+void
+device_register(struct device *dev, void *aux)
+{
+}
+
+struct nam2blk nam2blk[] = {
+ { "sd", 4 },
+ { "nbd", 20 },
+ { "tmpfsrd", 19 },
+ { "cd", 6},
+ { "wd", 0 },
+ { NULL, -1 }
+};
diff --git a/sys/arch/arm64/arm64/bus_dma.c b/sys/arch/arm64/arm64/bus_dma.c
new file mode 100644
index 00000000000..a51a6fcf40e
--- /dev/null
+++ b/sys/arch/arm64/arm64/bus_dma.c
@@ -0,0 +1,713 @@
+/* $OpenBSD: bus_dma.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
+ *
+ * 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 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.
+ *
+ */
+/*-
+ * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+
+#include <machine/bus.h>
+
+/*
+ * Common function for DMA map creation. May be called by bus-specific
+ * DMA map creation functions.
+ */
+int
+_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
+ bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
+{
+ struct machine_bus_dmamap *map;
+ void *mapstore;
+ size_t mapsize;
+
+ /*
+ * Allocate and initialize the DMA map. The end of the map
+ * is a variable-sized array of segments, so we allocate enough
+ * room for them in one shot.
+ *
+ * Note we don't preserve the WAITOK or NOWAIT flags. Preservation
+ * of ALLOCNOW notifies others that we've reserved these resources,
+ * and they are not to be freed.
+ *
+ * The bus_dmamap_t includes one bus_dma_segment_t, hence
+ * the (nsegments - 1).
+ */
+ mapsize = sizeof(struct machine_bus_dmamap) +
+ (sizeof(bus_dma_segment_t) * (nsegments - 1));
+ if ((mapstore = malloc(mapsize, M_DEVBUF, (flags & BUS_DMA_NOWAIT) ?
+ (M_NOWAIT | M_ZERO) : (M_WAITOK | M_ZERO))) == NULL)
+ return (ENOMEM);
+
+ map = (struct machine_bus_dmamap *)mapstore;
+ map->_dm_size = size;
+ map->_dm_segcnt = nsegments;
+ map->_dm_maxsegsz = maxsegsz;
+ map->_dm_boundary = boundary;
+ map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
+
+ *dmamp = map;
+ return (0);
+}
+
+/*
+ * Common function for DMA map destruction. May be called by bus-specific
+ * DMA map destruction functions.
+ */
+void
+_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
+{
+ free(map, M_DEVBUF, 0);
+}
+
+/*
+ * Common function for loading a DMA map with a linear buffer. May
+ * be called by bus-specific DMA map load functions.
+ */
+int
+_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen,
+ struct proc *p, int flags)
+{
+ paddr_t lastaddr;
+ int seg, error;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_nsegs = 0;
+ map->dm_mapsize = 0;
+
+ if (buflen > map->_dm_size)
+ return (EINVAL);
+
+ seg = 0;
+ error = (*t->_dmamap_load_buffer)(t, map, buf, buflen, p, flags,
+ &lastaddr, &seg, 1);
+ if (error == 0) {
+ map->dm_nsegs = seg + 1;
+ map->dm_mapsize = buflen;
+ }
+
+ return (error);
+}
+
+/*
+ * Like _bus_dmamap_load(), but for mbufs.
+ */
+int
+_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0, int flags)
+{
+ paddr_t lastaddr;
+ int seg, error, first;
+ struct mbuf *m;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_nsegs = 0;
+ map->dm_mapsize = 0;
+
+#ifdef DIAGNOSTIC
+ if ((m0->m_flags & M_PKTHDR) == 0)
+ panic("_dmamap_load_mbuf: no packet header");
+#endif
+
+ if (m0->m_pkthdr.len > map->_dm_size)
+ return (EINVAL);
+
+ first = 1;
+ seg = 0;
+ error = 0;
+ for (m = m0; m != NULL && error == 0; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ error = (*t->_dmamap_load_buffer)(t, map, m->m_data, m->m_len,
+ NULL, flags, &lastaddr, &seg, first);
+ first = 0;
+ }
+ if (error == 0) {
+ map->dm_nsegs = seg + 1;
+ map->dm_mapsize = m0->m_pkthdr.len;
+ }
+
+ return (error);
+}
+
+/*
+ * Like _dmamap_load(), but for uios.
+ */
+int
+_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags)
+{
+ paddr_t lastaddr;
+ int seg, i, error, first;
+ bus_size_t minlen, resid;
+ struct proc *p = NULL;
+ struct iovec *iov;
+ void *addr;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_nsegs = 0;
+ map->dm_mapsize = 0;
+
+ resid = uio->uio_resid;
+ iov = uio->uio_iov;
+
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ p = uio->uio_procp;
+#ifdef DIAGNOSTIC
+ if (p == NULL)
+ panic("_dmamap_load_uio: USERSPACE but no proc");
+#endif
+ }
+
+ first = 1;
+ seg = 0;
+ error = 0;
+ for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
+ /*
+ * Now at the first iovec to load. Load each iovec
+ * until we have exhausted the residual count.
+ */
+ minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
+ addr = (void *)iov[i].iov_base;
+
+ error = (*t->_dmamap_load_buffer)(t, map, addr, minlen,
+ p, flags, &lastaddr, &seg, first);
+ first = 0;
+
+ resid -= minlen;
+ }
+ if (error == 0) {
+ map->dm_nsegs = seg + 1;
+ map->dm_mapsize = uio->uio_resid;
+ }
+
+ return (error);
+}
+
+/*
+ * Like _dmamap_load(), but for raw memory allocated with
+ * bus_dmamem_alloc().
+ */
+int
+_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs,
+ int nsegs, bus_size_t size, int flags)
+{
+ if (nsegs > map->_dm_segcnt || size > map->_dm_size)
+ return (EINVAL);
+
+ /*
+ * Make sure we don't cross any boundaries.
+ */
+ if (map->_dm_boundary) {
+ bus_addr_t bmask = ~(map->_dm_boundary - 1);
+ int i;
+
+ if (t->_dma_mask != 0)
+ bmask &= t->_dma_mask;
+ for (i = 0; i < nsegs; i++) {
+ if (segs[i].ds_len > map->_dm_maxsegsz)
+ return (EINVAL);
+ if ((segs[i].ds_addr & bmask) !=
+ ((segs[i].ds_addr + segs[i].ds_len - 1) & bmask))
+ return (EINVAL);
+ }
+ }
+
+ bcopy(segs, map->dm_segs, nsegs * sizeof(*segs));
+ map->dm_nsegs = nsegs;
+ map->dm_mapsize = size;
+ return (0);
+}
+
+/*
+ * Common function for unloading a DMA map. May be called by
+ * bus-specific DMA map unload functions.
+ */
+void
+_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
+{
+ /*
+ * No resources to free; just mark the mappings as
+ * invalid.
+ */
+ map->dm_nsegs = 0;
+ map->dm_mapsize = 0;
+}
+
+/*
+ * Common function for DMA map synchronization. May be called
+ * by bus-specific DMA map synchronization functions.
+ */
+void
+_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t addr,
+ bus_size_t size, int op)
+{
+ int nsegs;
+ int curseg;
+ //struct cpu_info *ci = curcpu();
+
+ nsegs = map->dm_nsegs;
+ curseg = 0;
+
+ while (size && nsegs) {
+ paddr_t paddr;
+ vaddr_t vaddr;
+ bus_size_t ssize;
+
+ ssize = map->dm_segs[curseg].ds_len;
+ paddr = map->dm_segs[curseg]._ds_paddr;
+ vaddr = map->dm_segs[curseg]._ds_vaddr;
+
+ if (addr != 0) {
+ if (addr >= ssize) {
+ addr -= ssize;
+ ssize = 0;
+ } else {
+ vaddr += addr;
+ paddr += addr;
+ ssize -= addr;
+ addr = 0;
+ }
+ }
+ if (ssize > size)
+ ssize = size;
+
+#if 0
+ if (IS_XKPHYS(vaddr) && XKPHYS_TO_CCA(vaddr) == CCA_NC) {
+ size -= ssize;
+ ssize = 0;
+ }
+#endif
+
+ if (ssize != 0) {
+ /*
+ * If only PREWRITE is requested, writeback.
+ * PREWRITE with PREREAD writebacks
+ * and invalidates (if noncoherent) *all* cache levels.
+ * Otherwise, just invalidate (if noncoherent).
+ */
+ if (op & BUS_DMASYNC_PREWRITE) {
+ if (op & BUS_DMASYNC_PREREAD)
+#if 0
+ Mips_IOSyncDCache(ci, vaddr,
+ ssize, CACHE_SYNC_X);
+#else
+ ; // XXX MUST ADD CACHEFLUSHING
+#endif
+ else
+#if 0
+ Mips_IOSyncDCache(ci, vaddr,
+ ssize, CACHE_SYNC_W);
+#else
+ ; // XXX MUST ADD CACHEFLUSHING
+#endif
+ } else
+ if (op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_POSTREAD)) {
+#if 0
+ Mips_IOSyncDCache(ci, vaddr,
+ ssize, CACHE_SYNC_R);
+#else
+ ; // XXX MUST ADD CACHEFLUSHING
+#endif
+ }
+ size -= ssize;
+ }
+ curseg++;
+ nsegs--;
+ }
+
+ if (size != 0) {
+ panic("_dmamap_sync: ran off map!");
+ }
+}
+
+/*
+ * Common function for DMA-safe memory allocation. May be called
+ * by bus-specific DMA memory allocation functions.
+ */
+int
+_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
+ bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
+ int flags)
+{
+ return _dmamem_alloc_range(t, size, alignment, boundary,
+ segs, nsegs, rsegs, flags, (paddr_t)0, (paddr_t)-1);
+}
+
+/*
+ * Common function for freeing DMA-safe memory. May be called by
+ * bus-specific DMA memory free functions.
+ */
+void
+_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
+{
+ vm_page_t m;
+ bus_addr_t addr;
+ struct pglist mlist;
+ int curseg;
+ int success;
+ paddr_t pa;
+
+ /*
+ * Build a list of pages to free back to the VM system.
+ */
+ TAILQ_INIT(&mlist);
+ for (curseg = 0; curseg < nsegs; curseg++) {
+ for (addr = segs[curseg].ds_addr;
+ addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
+ addr += PAGE_SIZE) {
+ success = pmap_extract (pmap_kernel(), addr, &pa);
+ m = PHYS_TO_VM_PAGE(pa);
+ TAILQ_INSERT_TAIL(&mlist, m, pageq);
+ }
+ }
+
+ uvm_pglistfree(&mlist);
+}
+
+/*
+ * Common function for mapping DMA-safe memory. May be called by
+ * bus-specific DMA memory map functions.
+ */
+int
+_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, size_t size,
+ caddr_t *kvap, int flags)
+{
+ vaddr_t va, sva;
+ size_t ssize;
+ bus_addr_t addr;
+ int curseg, pmap_flags, cache;
+ const struct kmem_dyn_mode *kd;
+
+#if 0
+ if (nsegs == 1) {
+ (void)pmap_extract (pmap_kernel(), segs[0].ds_addr, &pa);
+ if (flags & (BUS_DMA_COHERENT | BUS_DMA_NOCACHE))
+ *kvap = (caddr_t)PHYS_TO_XKPHYS(pa, CCA_NC);
+ else
+ *kvap = (caddr_t)PHYS_TO_XKPHYS(pa, CCA_CACHED);
+ return (0);
+ }
+#endif
+
+ size = round_page(size);
+ kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok;
+ va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, kd);
+ if (va == 0)
+ return (ENOMEM);
+
+ *kvap = (caddr_t)va;
+
+ sva = va;
+ ssize = size;
+ pmap_flags = PMAP_WIRED | PMAP_CANFAIL;
+ cache = PMAP_CACHE_DEFAULT;
+ if (flags & (BUS_DMA_COHERENT | BUS_DMA_NOCACHE))
+ cache = PMAP_CACHE_DEV;
+ for (curseg = 0; curseg < nsegs; curseg++) {
+ for (addr = segs[curseg].ds_addr;
+ addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
+ addr += NBPG, va += NBPG, size -= NBPG) {
+ if (size == 0)
+ panic("_dmamem_map: size botch");
+ pmap_kenter_cache(va, addr,
+ PROT_READ | PROT_WRITE | pmap_flags,
+ cache);
+
+ /*
+ * This is redundant with what pmap_enter() did
+ * above, but will take care of forcing other
+ * mappings of the same page (if any) to be
+ * uncached.
+ * If there are no multiple mappings of that
+ * page, this amounts to a noop.
+ */
+#if 0
+ // XXX handle ?
+ if (flags & (BUS_DMA_COHERENT | BUS_DMA_NOCACHE))
+ pmap_page_cache(PHYS_TO_VM_PAGE(pa),
+ PGF_UNCACHED);
+#endif
+ }
+ pmap_update(pmap_kernel());
+ }
+
+ return (0);
+}
+
+/*
+ * Common function for unmapping DMA-safe memory. May be called by
+ * bus-specific DMA memory unmapping functions.
+ */
+void
+_dmamem_unmap(bus_dma_tag_t t, caddr_t kva, size_t size)
+{
+#if 0
+ if (IS_XKPHYS((vaddr_t)kva))
+ return;
+#endif
+
+ km_free(kva, round_page(size), &kv_any, &kp_none);
+}
+
+/*
+ * Common function for mmap(2)'ing DMA-safe memory. May be called by
+ * bus-specific DMA mmap(2)'ing functions.
+ */
+paddr_t
+_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, off_t off,
+ int prot, int flags)
+{
+ int i;
+ paddr_t pa;
+
+ for (i = 0; i < nsegs; i++) {
+#ifdef DIAGNOSTIC
+ if (off & PGOFSET)
+ panic("_dmamem_mmap: offset unaligned");
+ if (segs[i].ds_addr & PGOFSET)
+ panic("_dmamem_mmap: segment unaligned");
+ if (segs[i].ds_len & PGOFSET)
+ panic("_dmamem_mmap: segment size not multiple"
+ " of page size");
+#endif
+ if (off >= segs[i].ds_len) {
+ off -= segs[i].ds_len;
+ continue;
+ }
+
+ (void)pmap_extract (pmap_kernel(), segs[i].ds_addr, &pa);
+ return pa + off;
+ }
+
+ /* Page not found. */
+ return (-1);
+}
+
+/**********************************************************************
+ * DMA utility functions
+ **********************************************************************/
+
+/*
+ * Utility function to load a linear buffer. lastaddrp holds state
+ * between invocations (for multiple-buffer loads). segp contains
+ * the starting segment on entrance, and the ending segment on exit.
+ * first indicates if this is the first invocation of this function.
+ */
+int
+_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+ bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
+ int *segp, int first)
+{
+ bus_size_t sgsize;
+ bus_addr_t lastaddr, baddr, bmask;
+ paddr_t curaddr;
+ vaddr_t vaddr = (vaddr_t)buf;
+ int seg;
+ pmap_t pmap;
+
+ if (p != NULL)
+ pmap = p->p_vmspace->vm_map.pmap;
+ else
+ pmap = pmap_kernel();
+
+ lastaddr = *lastaddrp;
+ bmask = ~(map->_dm_boundary - 1);
+ if (t->_dma_mask != 0)
+ bmask &= t->_dma_mask;
+
+ for (seg = *segp; buflen > 0; ) {
+ /*
+ * Get the physical address for this segment.
+ */
+ if (pmap_extract(pmap, vaddr, &curaddr) == FALSE)
+ panic("_dmapmap_load_buffer: pmap_extract(%p, %lx) failed!",
+ pmap, vaddr);
+
+ /*
+ * Compute the segment size, and adjust counts.
+ */
+ sgsize = NBPG - ((u_long)vaddr & PGOFSET);
+ if (buflen < sgsize)
+ sgsize = buflen;
+
+ /*
+ * Make sure we don't cross any boundaries.
+ */
+ if (map->_dm_boundary > 0) {
+ baddr = ((bus_addr_t)curaddr + map->_dm_boundary) &
+ bmask;
+ if (sgsize > (baddr - (bus_addr_t)curaddr))
+ sgsize = (baddr - (bus_addr_t)curaddr);
+ }
+
+ /*
+ * Insert chunk into a segment, coalescing with
+ * previous segment if possible.
+ */
+ if (first) {
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ map->dm_segs[seg]._ds_paddr = curaddr;
+ map->dm_segs[seg]._ds_vaddr = vaddr;
+ first = 0;
+ } else {
+ if ((bus_addr_t)curaddr == lastaddr &&
+ (map->dm_segs[seg].ds_len + sgsize) <=
+ map->_dm_maxsegsz &&
+ (map->_dm_boundary == 0 ||
+ (map->dm_segs[seg].ds_addr & bmask) ==
+ ((bus_addr_t)curaddr & bmask)))
+ map->dm_segs[seg].ds_len += sgsize;
+ else {
+ if (++seg >= map->_dm_segcnt)
+ break;
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ map->dm_segs[seg]._ds_paddr = curaddr;
+ map->dm_segs[seg]._ds_vaddr = vaddr;
+ }
+ }
+
+ lastaddr = (bus_addr_t)curaddr + sgsize;
+ vaddr += sgsize;
+ buflen -= sgsize;
+ }
+
+ *segp = seg;
+ *lastaddrp = lastaddr;
+
+ /*
+ * Did we fit?
+ */
+ if (buflen != 0)
+ return (EFBIG); /* XXX better return value here? */
+
+ return (0);
+}
+
+/*
+ * Allocate physical memory from the given physical address range.
+ * Called by DMA-safe memory allocation methods.
+ */
+int
+_dmamem_alloc_range(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
+ bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
+ int flags, paddr_t low, paddr_t high)
+{
+ paddr_t curaddr, lastaddr;
+ vm_page_t m;
+ struct pglist mlist;
+ int curseg, error, plaflag;
+
+ /* Always round the size. */
+ size = round_page(size);
+
+ /*
+ * Allocate pages from the VM system.
+ */
+ plaflag = flags & BUS_DMA_NOWAIT ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK;
+ if (flags & BUS_DMA_ZERO)
+ plaflag |= UVM_PLA_ZERO;
+
+ TAILQ_INIT(&mlist);
+ error = uvm_pglistalloc(size, low, high, alignment, boundary,
+ &mlist, nsegs, plaflag);
+ if (error)
+ return (error);
+
+ /*
+ * Compute the location, size, and number of segments actually
+ * returned by the VM code.
+ */
+ m = TAILQ_FIRST(&mlist);
+ curseg = 0;
+ lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
+ segs[curseg].ds_len = PAGE_SIZE;
+ m = TAILQ_NEXT(m, pageq);
+
+ for (; m != NULL; m = TAILQ_NEXT(m, pageq)) {
+ curaddr = VM_PAGE_TO_PHYS(m);
+#ifdef DIAGNOSTIC
+ if (curaddr < low || curaddr >= high) {
+ printf("vm_page_alloc_memory returned non-sensical"
+ " address 0x%lx\n", curaddr);
+ panic("_dmamem_alloc_range");
+ }
+#endif
+ if (curaddr == (lastaddr + PAGE_SIZE))
+ segs[curseg].ds_len += PAGE_SIZE;
+ else {
+ curseg++;
+ segs[curseg].ds_addr = curaddr;
+ segs[curseg].ds_len = PAGE_SIZE;
+ }
+ lastaddr = curaddr;
+ }
+
+ *rsegs = curseg + 1;
+
+ return (0);
+}
diff --git a/sys/arch/arm64/arm64/conf.c b/sys/arch/arm64/arm64/conf.c
new file mode 100644
index 00000000000..625f59ec339
--- /dev/null
+++ b/sys/arch/arm64/arm64/conf.c
@@ -0,0 +1,387 @@
+/* $OpenBSD: conf.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 1994, 1995 Charles M. Hannum. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Charles Hannum.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 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/systm.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/vnode.h>
+
+#include <machine/conf.h>
+
+#include "wd.h"
+bdev_decl(wd);
+#include "sd.h"
+#include "st.h"
+#include "cd.h"
+#include "uk.h"
+#include "vnd.h"
+
+struct bdevsw bdevsw[] =
+{
+ bdev_disk_init(NWD,wd), /* 0: ST506/ESDI/IDE disk */
+ bdev_swap_init(1,sw), /* 1: swap pseudo-device */
+ bdev_notdef(), /* 2: was floppy diskette */
+ bdev_notdef(), /* 3 */
+ bdev_disk_init(NSD,sd), /* 4: SCSI disk */
+ bdev_notdef(), /* 5: was: SCSI tape */
+ bdev_disk_init(NCD,cd), /* 6: SCSI CD-ROM */
+ bdev_notdef(), /* 7 */
+ bdev_notdef(), /* 8 */
+ bdev_notdef(), /* 9 */
+ bdev_notdef(), /* 10 */
+ bdev_notdef(), /* 11 */
+ bdev_notdef(), /* 12 */
+ bdev_notdef(), /* 13 */
+ bdev_disk_init(NVND,vnd), /* 14: vnode disk driver */
+ bdev_notdef(), /* 15: was: Sony CD-ROM */
+ bdev_notdef(), /* 16: was: concatenated disk driver */
+ bdev_notdef(), /* 17: was: rd(4) ramdisk driver */
+ bdev_notdef(), /* 18 */
+};
+int nblkdev = nitems(bdevsw);
+
+/* open, close, read, write, ioctl, tty, mmap */
+#define cdev_pc_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), dev_init(c,n,stop), \
+ dev_init(c,n,tty), ttselect, dev_init(c,n,mmap), D_TTY }
+
+/* open, close, read, ioctl */
+#define cdev_joy_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, seltrue, \
+ (dev_type_mmap((*))) enodev }
+
+/* open, close, ioctl, select -- XXX should be a generic device */
+#define cdev_ocis_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \
+ (dev_type_mmap((*))) enodev, 0 }
+
+/* open, close, read */
+#define cdev_nvram_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ (dev_type_write((*))) enodev, (dev_type_ioctl((*))) enodev, \
+ (dev_type_stop((*))) enodev, 0, seltrue, \
+ (dev_type_mmap((*))) enodev, 0 }
+
+
+#define mmread mmrw
+#define mmwrite mmrw
+cdev_decl(mm);
+cdev_decl(wd);
+#include "bio.h"
+#include "pty.h"
+#include "com.h"
+cdev_decl(com);
+#include "lpt.h"
+cdev_decl(lpt);
+#include "ch.h"
+#include "bpfilter.h"
+cdev_decl(spkr);
+#include "tun.h"
+#include "audio.h"
+#include "video.h"
+#include "midi.h"
+#include "bktr.h"
+#include "ksyms.h"
+#include "usb.h"
+#include "uhid.h"
+#include "ugen.h"
+#include "ulpt.h"
+#include "ucom.h"
+#include "radio.h"
+#include "drm.h"
+cdev_decl(drm);
+
+#include "wsdisplay.h"
+#include "wskbd.h"
+#include "wsmouse.h"
+#include "wsmux.h"
+
+#ifdef USER_PCICONF
+#include "pci.h"
+cdev_decl(pci);
+#endif
+
+#include "pf.h"
+#include "hotplug.h"
+#include "vscsi.h"
+#include "pppx.h"
+#include "fuse.h"
+
+struct cdevsw cdevsw[] =
+{
+ cdev_cn_init(1,cn), /* 0: virtual console */
+ cdev_ctty_init(1,ctty), /* 1: controlling terminal */
+ cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */
+ cdev_disk_init(NWD,wd), /* 3: ST506/ESDI/IDE disk */
+ cdev_notdef(), /* 4 was /dev/drum */
+ cdev_tty_init(NPTY,pts), /* 5: pseudo-tty slave */
+ cdev_ptc_init(NPTY,ptc), /* 6: pseudo-tty master */
+ cdev_log_init(1,log), /* 7: /dev/klog */
+ cdev_tty_init(NCOM,com), /* 8: serial port */
+ cdev_notdef(), /* 9: was floppy disk */
+ cdev_notdef(), /* 10 */
+ cdev_notdef(), /* 11: Sony CD-ROM */
+ cdev_wsdisplay_init(NWSDISPLAY, /* 12: frame buffers, etc. */
+ wsdisplay),
+ cdev_disk_init(NSD,sd), /* 13: SCSI disk */
+ cdev_notdef(), /* 14: was: SCSI tape */
+ cdev_disk_init(NCD,cd), /* 15: SCSI CD-ROM */
+ cdev_lpt_init(NLPT,lpt), /* 16: parallel printer */
+ cdev_ch_init(NCH,ch), /* 17: SCSI autochanger */
+ cdev_notdef(), /* 18: was: concatenated disk driver */
+ cdev_notdef(), /* 19 */
+ cdev_uk_init(NUK,uk), /* 20: unknown SCSI */
+ cdev_notdef(), /* 21 */
+ cdev_fd_init(1,filedesc), /* 22: file descriptor pseudo-device */
+ cdev_bpf_init(NBPFILTER,bpf), /* 23: Berkeley packet filter */
+ cdev_notdef(), /* 24 */
+ cdev_notdef(), /* 25 */
+ cdev_notdef(), /* 26 */
+ cdev_notdef(), /* 27 */
+ cdev_notdef(), /* 28 was LKM */
+ cdev_notdef(), /* 29 */
+ cdev_notdef(), /* 30 */
+ cdev_notdef(), /* 31 */
+ cdev_notdef(), /* 32 */
+ cdev_notdef(), /* 33 */
+ cdev_notdef(), /* 34 */
+ cdev_notdef(), /* 35: Microsoft mouse */
+ cdev_notdef(), /* 36: Logitech mouse */
+ cdev_notdef(), /* 37: Extended PS/2 mouse */
+ cdev_notdef(), /* 38: was: Cyclom serial port */
+ cdev_notdef(), /* 39: Mitsumi CD-ROM */
+ cdev_tun_init(NTUN,tun), /* 40: network tunnel */
+ cdev_disk_init(NVND,vnd), /* 41: vnode disk driver */
+ cdev_audio_init(NAUDIO,audio), /* 42: generic audio I/O */
+ cdev_notdef(), /* 43 */
+ cdev_video_init(NVIDEO,video), /* 44: generic video I/O */
+ cdev_random_init(1,random), /* 45: random data source */
+ cdev_notdef(), /* 46 */
+ cdev_notdef(), /* 47 */
+ cdev_notdef(), /* 48 */
+ cdev_bktr_init(NBKTR,bktr), /* 49: Bt848 video capture device */
+ cdev_ksyms_init(NKSYMS,ksyms), /* 50: Kernel symbols device */
+ cdev_notdef(), /* 51 */
+ cdev_midi_init(NMIDI,midi), /* 52: MIDI I/O */
+ cdev_notdef(), /* 53 was: sequencer I/O */
+ cdev_notdef(), /* 54 was: RAIDframe disk driver */
+ cdev_notdef(), /* 55: */
+ /* The following slots are reserved for isdn4bsd. */
+ cdev_notdef(), /* 56: i4b main device */
+ cdev_notdef(), /* 57: i4b control device */
+ cdev_notdef(), /* 58: i4b raw b-channel access */
+ cdev_notdef(), /* 59: i4b trace device */
+ cdev_notdef(), /* 60: i4b phone device */
+ /* End of reserved slots for isdn4bsd. */
+ cdev_usb_init(NUSB,usb), /* 61: USB controller */
+ cdev_usbdev_init(NUHID,uhid), /* 62: USB generic HID */
+ cdev_usbdev_init(NUGEN,ugen), /* 63: USB generic driver */
+ cdev_ulpt_init(NULPT,ulpt), /* 64: USB printers */
+ cdev_notdef(), /* 65: urio */
+ cdev_tty_init(NUCOM,ucom), /* 66: USB tty */
+ cdev_mouse_init(NWSKBD, wskbd), /* 67: keyboards */
+ cdev_mouse_init(NWSMOUSE, /* 68: mice */
+ wsmouse),
+ cdev_mouse_init(NWSMUX, wsmux), /* 69: ws multiplexor */
+ cdev_notdef(), /* 70: was: /dev/crypto */
+ cdev_notdef(), /* 71: was: Cyclades-Z serial port */
+#ifdef USER_PCICONF
+ cdev_pci_init(NPCI,pci), /* 72: PCI user */
+#else
+ cdev_notdef(),
+#endif
+ cdev_pf_init(NPF,pf), /* 73: packet filter */
+ cdev_notdef(), /* 74: ALTQ (deprecated) */
+ cdev_notdef(),
+ cdev_radio_init(NRADIO, radio), /* 76: generic radio I/O */
+ cdev_notdef(), /* 77: was USB scanners */
+ cdev_notdef(), /* 78: was: system call tracing */
+ cdev_bio_init(NBIO,bio), /* 79: ioctl tunnel */
+ cdev_notdef(), /* 80: gpr? XXX */
+ cdev_ptm_init(NPTY,ptm), /* 81: pseudo-tty ptm device */
+ cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */
+ cdev_notdef(), /* 83 */
+ cdev_notdef(), /* 84 */
+ cdev_notdef(), /* 85 */
+ cdev_notdef(), /* 86 */
+ cdev_drm_init(NDRM,drm), /* 87: drm */
+ cdev_notdef(), /* 88 */
+ cdev_vscsi_init(NVSCSI,vscsi), /* 89: vscsi */
+ cdev_disk_init(1,diskmap), /* 90: disk mapper */
+ cdev_pppx_init(NPPPX,pppx), /* 91: pppx */
+ cdev_fuse_init(NFUSE,fuse), /* 92: fuse */
+};
+int nchrdev = nitems(cdevsw);
+
+/*
+ * Swapdev is a fake device implemented
+ * in sw.c used only internally to get to swstrategy.
+ * It cannot be provided to the users, because the
+ * swstrategy routine munches the b_dev and b_blkno entries
+ * before calling the appropriate driver. This would horribly
+ * confuse, e.g. the hashing routines. Instead, /dev/drum is
+ * provided as a character (raw) device.
+ */
+dev_t swapdev = makedev(BMAJ_SW, 0);
+
+/*
+ * Returns true if dev is /dev/mem or /dev/kmem.
+ */
+int
+iskmemdev(dev_t dev)
+{
+
+ return (major(dev) == CMAJ_MM && (minor(dev) < 2 || minor(dev) == 14));
+}
+
+/*
+ * Returns true if dev is /dev/zero.
+ */
+int
+iszerodev(dev_t dev)
+{
+
+ return (major(dev) == CMAJ_MM && minor(dev) == 12);
+}
+
+dev_t
+getnulldev(void)
+{
+ return makedev(CMAJ_MM, 2);
+}
+
+int chrtoblktbl[] = {
+ /*VCHR*/ /*VBLK*/
+ /* 0 */ NODEV,
+ /* 1 */ NODEV,
+ /* 2 */ NODEV,
+ /* 3 */ 0, /* wd */
+ /* 4 */ NODEV,
+ /* 5 */ NODEV,
+ /* 6 */ NODEV,
+ /* 7 */ NODEV,
+ /* 8 */ NODEV,
+ /* 9 */ NODEV, /* was fd */
+ /* 10 */ NODEV,
+ /* 11 */ NODEV,
+ /* 12 */ NODEV,
+ /* 13 */ 4, /* sd */
+ /* 14 */ 5, /* st */
+ /* 15 */ 6, /* cd */
+ /* 16 */ NODEV,
+ /* 17 */ NODEV,
+ /* 18 */ NODEV,
+ /* 19 */ NODEV,
+ /* 20 */ NODEV,
+ /* 21 */ NODEV,
+ /* 22 */ NODEV,
+ /* 23 */ NODEV,
+ /* 24 */ NODEV,
+ /* 25 */ NODEV,
+ /* 26 */ NODEV,
+ /* 27 */ NODEV,
+ /* 28 */ NODEV,
+ /* 29 */ NODEV,
+ /* 30 */ NODEV,
+ /* 31 */ NODEV,
+ /* 32 */ NODEV,
+ /* 33 */ NODEV,
+ /* 34 */ NODEV,
+ /* 35 */ NODEV,
+ /* 36 */ NODEV,
+ /* 37 */ NODEV,
+ /* 38 */ NODEV,
+ /* 39 */ NODEV,
+ /* 40 */ NODEV,
+ /* 41 */ 14, /* vnd */
+ /* 42 */ NODEV,
+ /* 43 */ NODEV,
+ /* 44 */ NODEV,
+ /* 45 */ NODEV,
+ /* 46 */ NODEV,
+ /* 47 */ NODEV,
+};
+
+int nchrtoblktbl = nitems(chrtoblktbl);
+
+/*
+ * In order to map BSD bdev numbers of disks to their BIOS equivalents
+ * we use several heuristics, one being using checksums of the first
+ * few blocks of a disk to get a signature we can match with /boot's
+ * computed signatures. To know where from to read, we must provide a
+ * disk driver name -> bdev major number table, which follows.
+ * Note: floppies are not included as those are differentiated by the BIOS.
+ */
+int findblkmajor(struct device *dv);
+dev_t dev_rawpart(struct device *); /* XXX */
+
+dev_t
+dev_rawpart(struct device *dv)
+{
+ int majdev;
+
+ majdev = findblkmajor(dv);
+
+ switch (majdev) {
+ /* add here any device you want to be checksummed on boot */
+ case BMAJ_WD:
+ case BMAJ_SD:
+ return (MAKEDISKDEV(majdev, dv->dv_unit, RAW_PART));
+ break;
+ default:
+ ;
+ }
+
+ return (NODEV);
+}
+
+#include <dev/cons.h>
+
+cons_decl(com);
+cons_decl(ws);
+
+struct consdev constab[] = {
+#if NWSDISPLAY > 0
+ cons_init(ws),
+#endif
+#if NCOM > 0
+ cons_init(com),
+#endif
+ { 0 },
+};
diff --git a/sys/arch/arm64/arm64/copy.S b/sys/arch/arm64/arm64/copy.S
new file mode 100644
index 00000000000..4d00cfc5a00
--- /dev/null
+++ b/sys/arch/arm64/arm64/copy.S
@@ -0,0 +1,120 @@
+/* $OpenBSD: copy.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ * Copyright (c) 2014 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 "assym.h"
+#include <sys/syscall.h>
+#include <machine/asm.h>
+#include <sys/errno.h>
+
+ .text
+ .align 2
+
+/*
+ * x0 = user space address
+ * x1 = kernel space address
+ * x2 = length
+ *
+ * Copies bytes from user space to kernel space
+ *
+ * XXX should this assert that address spaces are correct for each address?
+ */
+ENTRY(copyin)
+ cbnz x2, 1f
+ mov x0, 0
+ ret
+1:
+ mrs x3, tpidr_el1 // load cpuinfo
+ ldr x3, [x3, #(CI_CURPCB)]
+ ldr x4, [x3, #(PCB_ONFAULT)]
+ adr x5, .Lcopyfault
+ str x5, [x3, #(PCB_ONFAULT)] // set handler
+
+// This probably should be optimized
+2: ldrb w6, [x0], #1
+ strb w6, [x1], #1
+ sub x2, x2, #1
+ cbnz x2, 2b
+
+ str x4, [x3, #(PCB_ONFAULT)] // clear handler
+ mov x0, xzr
+ ret
+
+.Lcopyfault:
+ mov x0, #EFAULT
+ ldr x4, [x3, #(PCB_ONFAULT)]
+ ret
+
+/*
+ * x0 = kernel space address
+ * x1 = user space address
+ * x2 = length
+ *
+ * Copies bytes from kernel space to user space
+ *
+ * XXX should this assert that address spaces are correct for each address?
+ */
+
+ENTRY(copyout)
+ cbnz x2, 1f
+ mov x0, 0
+ ret
+1:
+ mrs x3, tpidr_el1 // load cpuinfo
+ ldr x3, [x3, #(CI_CURPCB)]
+ ldr x4, [x3, #(PCB_ONFAULT)]
+ adr x5, .Lcopyfault
+ str x5, [x3, #(PCB_ONFAULT)] // set handler
+
+// This probably should be optimized
+2: ldrb w6, [x0], #1
+ strb w6, [x1], #1
+ sub x2, x2, #1
+ cbnz x2, 2b
+
+ str x4, [x3, #(PCB_ONFAULT)] // clear handler
+ mov x0, xzr
+ ret
+
+/*
+ * x0 = kernel space source address
+ * x1 = kernel space destination address
+ * x2 = length
+ *
+ * Copies bytes from kernel space to kernel space, aborting on page fault
+ */
+
+ENTRY(kcopy)
+ cbnz x2, 1f
+ mov x0, 0
+ ret
+1:
+ mrs x3, tpidr_el1 // load cpuinfo
+ ldr x3, [x3, #(CI_CURPCB)]
+ ldr x4, [x3, #(PCB_ONFAULT)]
+ adr x5, .Lcopyfault
+ str x5, [x3, #(PCB_ONFAULT)] // set handler
+
+// This probably should be optimized
+2: ldrb w6, [x0], #1
+ strb w6, [x1], #1
+ sub x2, x2, #1
+ cbnz x2, 2b
+
+ str x4, [x3, #(PCB_ONFAULT)] // clear handler
+ mov x0, xzr
+ ret
diff --git a/sys/arch/arm64/arm64/copystr.S b/sys/arch/arm64/arm64/copystr.S
new file mode 100644
index 00000000000..2be74817ba3
--- /dev/null
+++ b/sys/arch/arm64/arm64/copystr.S
@@ -0,0 +1,93 @@
+/* $OpenBSD: copystr.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ * Copyright (c) 2014 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 "assym.h"
+#include <machine/asm.h>
+#include <sys/errno.h>
+#include <sys/errno.h>
+
+ .text
+ .align 2
+
+/*
+ * x0 - from
+ * x1 - to
+ * x2 - maxlens
+ * x3 - lencopied
+ * x4 - scratch
+ * x5 - hold old onfault
+ *
+ * Copy string from x0 to x1
+ */
+ENTRY(copystr)
+ mrs x6, tpidr_el1 // load curcpu
+ ldr x6, [x6, #(CI_CURPCB)]
+ ldr x5, [x6, #(PCB_ONFAULT)]
+ adr x7, .Lcopystrfault
+// set handler
+ str x7, [x6, #(PCB_ONFAULT)]
+
+ mov x8, xzr
+
+1: ldrb w4, [x0], 1
+ strb w4, [x1], #1
+ sub x2, x2, #1
+ add x8, x8, #1
+ cbz w4, .Lcopystrsuccess
+ cbnz x2, 1b
+
+ mov x0, #ENAMETOOLONG
+ b .Lcopystrcleanup
+
+.Lcopystrfault:
+ mov x0, #EFAULT
+ b .Lcopystrcleanup
+
+.Lcopystrsuccess:
+ mov x0, xzr
+
+.Lcopystrcleanup:
+ cbz x3, 2f
+ str x8, [x3]
+2:
+ str x5, [x6, #(PCB_ONFAULT)]
+ ret
+
+/*
+ * x0 - user space address
+ * x1 - kernel space address
+ * x2 - maxlens
+ * x3 - lencopied
+ *
+ * Copy string from user space to kernel space
+ */
+ENTRY(copyinstr)
+// XXX verify that x0 is user and x1 is kernel
+ b copystr
+
+/*
+ * x0 - kernel space address
+ * x1 - user space address
+ * x2 - maxlens
+ * x3 - lencopied
+ *
+ * Copy string from kernel space to user space
+ */
+ENTRY(copyoutstr)
+// XXX verify that x0 is kernel and x1 is user
+ b copystr
diff --git a/sys/arch/arm64/arm64/cpuswitch.S b/sys/arch/arm64/arm64/cpuswitch.S
new file mode 100644
index 00000000000..a97fddc64e8
--- /dev/null
+++ b/sys/arch/arm64/arm64/cpuswitch.S
@@ -0,0 +1,104 @@
+/* $OpenBSD: cpuswitch.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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 "assym.h"
+
+/*
+ * cpu_switchto(struct proc *oldproc, struct proc *newproc)
+ * x0 'struct proc *' of the old context
+ * x1 'struct proc *' of the new context
+ * x2 - may contain curcpu
+ * x3 - may contain switchframe pointer (new or old)
+ * x4 - may contain user thread pointer (TCB)
+ * x5 - may contain PCB pointer (new or old)
+ */
+ENTRY(cpu_switchto)
+ // check if old context needs to be saved
+ cmp x0, #0
+ beq 1f
+
+ // create switchframe
+ sub sp, sp, #(SWITCHFRAME_SZ)
+ mov x3, sp
+ stp x19, x20, [x3, #(SF_X19)]
+ stp x21, x22, [x3, #(SF_X21)]
+ stp x23, x24, [x3, #(SF_X23)]
+ stp x25, x26, [x3, #(SF_X25)]
+ stp x27, x28, [x3, #(SF_X27)]
+ stp x29, x30, [x3, #(SF_X29)]
+
+ mrs x2, tpidr_el1 // load curcpu
+ ldr x5, [x2, #(CI_CURPCB)]
+ str x3, [x5, #(PCB_SP) ] // save to old pcb
+
+
+ mov x19, x1 //save new ctx across vfp
+ // old process has been saved
+ // save old fpu?
+ ldr w7, [x5, #(PCB_FLAGS)]
+ mov w3, #(PCB_FPU)
+ and w7, w7, w3
+ cbz w7, 1f
+
+ bl vfp_save
+
+ mov x1, x19
+1:
+
+ mrs x2, tpidr_el1 // load curcpu
+ mov w5, #SONPROC
+ strb w5, [x1, #(P_STAT) ] // Mark new on cpu
+ ldr x5, [x1, #(P_ADDR) ] // load new pcb
+ str x5, [x2, #(CI_CURPCB)]
+ ldr x20, [x5, #(PCB_PAGEDIR)]
+ str x1, [x2, #(CI_CURPROC)]
+
+ ldr x4, [x5, #(PCB_TCB)]
+ msr tpidr_el0, x4 // load user tls
+
+ ldr x19, [x5, #(PCB_SP) ] // load new stack pointer
+ //msr ttbr0_el1, x20
+ mov x0, x1
+ mov x1, x20
+ mov x2, x5
+ bl pmap_setttb
+ mov x3, x19
+
+ mov sp, x3
+
+ ldp x19, x20, [x3, #(SF_X19)]
+ ldp x21, x22, [x3, #(SF_X21)]
+ ldp x23, x24, [x3, #(SF_X23)]
+ ldp x25, x26, [x3, #(SF_X25)]
+ ldp x27, x28, [x3, #(SF_X27)]
+ ldp x29, x30, [x3, #(SF_X29)]
+ add sp, sp, #(SWITCHFRAME_SZ)
+ ret
+
+ENTRY(proc_trampoline)
+#ifdef MULTIPROCESSOR
+ bl _C_LABEL(proc_trampoline_mp)
+#endif
+ // call it or just set the variable?
+ mov x0, IPL_NONE
+ bl spllower
+ mov x0, x20
+ blr x19
+ b syscall_return
+
+
diff --git a/sys/arch/arm64/arm64/db_disasm.c b/sys/arch/arm64/arm64/db_disasm.c
new file mode 100644
index 00000000000..a27762d3098
--- /dev/null
+++ b/sys/arch/arm64/arm64/db_disasm.c
@@ -0,0 +1,29 @@
+/* $OpenBSD: db_disasm.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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 <machine/db_machdep.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_output.h>
+#include <ddb/db_access.h>
+
+vaddr_t
+db_disasm(vaddr_t loc, boolean_t altfmt)
+{
+ return loc + 4;
+}
diff --git a/sys/arch/arm64/arm64/db_interface.c b/sys/arch/arm64/arm64/db_interface.c
new file mode 100644
index 00000000000..440a29729fb
--- /dev/null
+++ b/sys/arch/arm64/arm64/db_interface.c
@@ -0,0 +1,372 @@
+/* $OpenBSD: db_interface.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: db_interface.c,v 1.34 2003/10/26 23:11:15 chris Exp $ */
+
+/*
+ * Copyright (c) 1996 Scott K. Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+#include <sys/systm.h> /* just for boothowto */
+#include <sys/exec.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <arm64/db_machdep.h>
+#include <machine/pmap.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_interface.h>
+#include <dev/cons.h>
+
+//static long nil;
+
+int db_access_und_sp (struct db_variable *, db_expr_t *, int);
+int db_access_abt_sp (struct db_variable *, db_expr_t *, int);
+int db_access_irq_sp (struct db_variable *, db_expr_t *, int);
+u_int db_fetch_reg (int, db_regs_t *);
+
+int db_trapper (u_int, u_int, trapframe_t *, int);
+
+struct db_variable db_regs[] = {
+ { "x0", (long *)&DDB_REGS->tf_x[0], FCN_NULL, },
+ { "x1", (long *)&DDB_REGS->tf_x[1], FCN_NULL, },
+ { "x2", (long *)&DDB_REGS->tf_x[2], FCN_NULL, },
+ { "x3", (long *)&DDB_REGS->tf_x[3], FCN_NULL, },
+ { "x4", (long *)&DDB_REGS->tf_x[4], FCN_NULL, },
+ { "x5", (long *)&DDB_REGS->tf_x[5], FCN_NULL, },
+ { "x6", (long *)&DDB_REGS->tf_x[6], FCN_NULL, },
+ { "x7", (long *)&DDB_REGS->tf_x[7], FCN_NULL, },
+ { "x8", (long *)&DDB_REGS->tf_x[8], FCN_NULL, },
+ { "x9", (long *)&DDB_REGS->tf_x[9], FCN_NULL, },
+ { "x10", (long *)&DDB_REGS->tf_x[10], FCN_NULL, },
+ { "x11", (long *)&DDB_REGS->tf_x[11], FCN_NULL, },
+ { "x12", (long *)&DDB_REGS->tf_x[12], FCN_NULL, },
+ { "x13", (long *)&DDB_REGS->tf_x[13], FCN_NULL, },
+ { "x14", (long *)&DDB_REGS->tf_x[14], FCN_NULL, },
+ { "x15", (long *)&DDB_REGS->tf_x[15], FCN_NULL, },
+ { "x16", (long *)&DDB_REGS->tf_x[16], FCN_NULL, },
+ { "x17", (long *)&DDB_REGS->tf_x[17], FCN_NULL, },
+ { "x18", (long *)&DDB_REGS->tf_x[18], FCN_NULL, },
+ { "x19", (long *)&DDB_REGS->tf_x[19], FCN_NULL, },
+ { "x20", (long *)&DDB_REGS->tf_x[20], FCN_NULL, },
+ { "x21", (long *)&DDB_REGS->tf_x[21], FCN_NULL, },
+ { "x22", (long *)&DDB_REGS->tf_x[22], FCN_NULL, },
+ { "x23", (long *)&DDB_REGS->tf_x[23], FCN_NULL, },
+ { "x24", (long *)&DDB_REGS->tf_x[24], FCN_NULL, },
+ { "x25", (long *)&DDB_REGS->tf_x[25], FCN_NULL, },
+ { "x26", (long *)&DDB_REGS->tf_x[26], FCN_NULL, },
+ { "x27", (long *)&DDB_REGS->tf_x[27], FCN_NULL, },
+ { "x28", (long *)&DDB_REGS->tf_x[28], FCN_NULL, },
+ { "x29", (long *)&DDB_REGS->tf_x[29], FCN_NULL, },
+ { "x30", (long *)&DDB_REGS->tf_x[30], FCN_NULL, },
+ { "sp", (long *)&DDB_REGS->tf_sp, FCN_NULL, },
+ { "spsr", (long *)&DDB_REGS->tf_spsr, FCN_NULL, },
+ { "elr", (long *)&DDB_REGS->tf_elr, FCN_NULL, },
+ { "lr", (long *)&DDB_REGS->tf_lr, FCN_NULL, },
+};
+
+extern label_t *db_recover;
+
+struct db_variable * db_eregs = db_regs + nitems(db_regs);
+
+int db_active = 0;
+
+#ifdef DDB
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+int
+kdb_trap(int type, db_regs_t *regs)
+{
+ int s;
+
+ switch (type) {
+ case T_BREAKPOINT: /* breakpoint */
+ case -1: /* keyboard interrupt */
+ break;
+ default:
+ if (db_recover != 0) {
+ /* This will longjmp back into db_command_loop() */
+ db_error("Faulted in DDB; continuing...\n");
+ /*NOTREACHED*/
+ }
+ }
+
+ /* Should switch to kdb`s own stack here. */
+
+ ddb_regs = *regs;
+
+ s = splhigh();
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, 0/*code*/);
+ cnpollc(FALSE);
+ db_active--;
+ splx(s);
+
+ *regs = ddb_regs;
+
+ return (1);
+}
+#endif
+
+
+static int db_validate_address(vaddr_t addr);
+
+static int
+db_validate_address(vaddr_t addr)
+{
+ struct proc *p = curproc;
+ struct pmap *pmap;
+
+ if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap ||
+#ifndef ARM32_NEW_VM_LAYOUT
+ addr >= VM_MAXUSER_ADDRESS
+#else
+ addr >= VM_MIN_KERNEL_ADDRESS
+#endif
+ )
+ pmap = pmap_kernel();
+ else
+ pmap = p->p_vmspace->vm_map.pmap;
+
+ return (pmap_extract(pmap, addr, NULL) == FALSE);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+void
+db_read_bytes(addr, size, data)
+ vaddr_t addr;
+ size_t size;
+ char *data;
+{
+ char *src = (char *)addr;
+
+ if (db_validate_address((u_int)src)) {
+ db_printf("address %p is invalid\n", src);
+ return;
+ }
+
+ if (size == 4 && (addr & 3) == 0 && ((u_int32_t)data & 3) == 0) {
+ *((int*)data) = *((int*)src);
+ return;
+ }
+
+ if (size == 2 && (addr & 1) == 0 && ((u_int32_t)data & 1) == 0) {
+ *((short*)data) = *((short*)src);
+ return;
+ }
+
+ while (size-- > 0) {
+ if (db_validate_address((u_int)src)) {
+ db_printf("address %p is invalid\n", src);
+ return;
+ }
+ *data++ = *src++;
+ }
+}
+
+#if 0
+static void
+db_write_text(vaddr_t addr, size_t size, char *data)
+{
+ // Implement
+ return ;
+}
+#endif
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(vaddr_t addr, size_t size, char *data)
+{
+#if 0
+ extern char etext[];
+ extern char kernel_text[];
+ char *dst;
+ size_t loop;
+
+ /* If any part is in kernel text, use db_write_text() */
+ if (addr >= (vaddr_t) kernel_text && addr < (vaddr_t) etext) {
+ db_write_text(addr, size, data);
+ return;
+ }
+
+ dst = (char *)addr;
+ loop = size;
+ while (loop-- > 0) {
+ if (db_validate_address((u_int)dst)) {
+ db_printf("address %p is invalid\n", dst);
+ return;
+ }
+ *dst++ = *data++;
+ }
+ /* make sure the caches and memory are in sync */
+ cpu_icache_sync_range(addr, size);
+
+ /* In case the current page tables have been modified ... */
+ cpu_tlb_flushID();
+ cpu_cpwait();
+#endif
+}
+
+void
+Debugger(void)
+{
+ asm("brk 0");
+}
+
+struct db_command db_machine_command_table[] = {
+ { NULL, NULL, 0, NULL }
+};
+
+int
+db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code)
+{
+
+ if (fault_code == EXCP_BRK) {
+ kdb_trap(T_BREAKPOINT, frame);
+ frame->tf_elr += INSN_SIZE;
+ } else
+ kdb_trap(-1, frame);
+ return (0);
+}
+
+extern u_int esym;
+extern u_int end;
+
+void
+db_machine_init(void)
+{
+ /*
+ * We get called before malloc() is available, so supply a static
+ * struct undefined_handler.
+ */
+ //db_uh.uh_handler = db_trapper;
+ //install_coproc_handler_static(0, &db_uh);
+
+ db_machine_commands_install(db_machine_command_table);
+}
+
+u_int
+db_fetch_reg(int reg, db_regs_t *db_regs)
+{
+
+ switch (reg) {
+ case 0:
+ return (db_regs->tf_x[0]);
+ case 1:
+ return (db_regs->tf_x[1]);
+ case 2:
+ return (db_regs->tf_x[2]);
+ case 3:
+ return (db_regs->tf_x[3]);
+ case 4:
+ return (db_regs->tf_x[4]);
+ case 5:
+ return (db_regs->tf_x[5]);
+ case 6:
+ return (db_regs->tf_x[6]);
+ case 7:
+ return (db_regs->tf_x[7]);
+ case 8:
+ return (db_regs->tf_x[8]);
+ case 9:
+ return (db_regs->tf_x[9]);
+ case 10:
+ return (db_regs->tf_x[10]);
+ case 11:
+ return (db_regs->tf_x[11]);
+ case 12:
+ return (db_regs->tf_x[12]);
+ case 13:
+ return (db_regs->tf_x[13]);
+ case 14:
+ return (db_regs->tf_x[14]);
+ case 15:
+ return (db_regs->tf_x[15]);
+ case 16:
+ return (db_regs->tf_x[16]);
+ case 17:
+ return (db_regs->tf_x[17]);
+ case 18:
+ return (db_regs->tf_x[18]);
+ case 19:
+ return (db_regs->tf_x[19]);
+ case 20:
+ return (db_regs->tf_x[20]);
+ case 21:
+ return (db_regs->tf_x[21]);
+ case 22:
+ return (db_regs->tf_x[22]);
+ case 23:
+ return (db_regs->tf_x[23]);
+ case 24:
+ return (db_regs->tf_x[24]);
+ case 25:
+ return (db_regs->tf_x[25]);
+ case 26:
+ return (db_regs->tf_x[26]);
+ case 27:
+ return (db_regs->tf_x[27]);
+ case 28:
+ return (db_regs->tf_x[28]);
+ case 29:
+ return (db_regs->tf_x[29]);
+ case 30:
+ return (db_regs->tf_lr);
+ case 31:
+ return (db_regs->tf_sp);
+ case 32:
+ return (db_regs->tf_elr);
+ case 33:
+ return (db_regs->tf_spsr);
+ default:
+ panic("db_fetch_reg: botch");
+ }
+}
+
+db_addr_t
+db_branch_taken(u_int insn, db_addr_t pc, db_regs_t *db_regs)
+{
+ // implment
+ return pc + 4;
+}
diff --git a/sys/arch/arm64/arm64/db_trace.c b/sys/arch/arm64/arm64/db_trace.c
new file mode 100644
index 00000000000..2dab0d3ec45
--- /dev/null
+++ b/sys/arch/arm64/arm64/db_trace.c
@@ -0,0 +1,96 @@
+/* $OpenBSD: db_trace.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2000, 2001 Ben Harris
+ * Copyright (c) 1996 Scott K. Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <arm64/armreg.h>
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_output.h>
+
+db_regs_t ddb_regs;
+
+#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+#ifndef __clang__
+/*
+ * Clang uses a different stack frame, which looks like the following.
+ *
+ * return link value [fp, #+4]
+ * return fp value [fp] <- fp points to here
+ *
+ */
+#define FR_RFP (0x0)
+#define FR_RLV (+0x4)
+#endif /* !__clang__ */
+
+void
+db_stack_trace_print(addr, have_addr, count, modif, pr)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+ int (*pr) (const char *, ...);
+{
+ u_int32_t frame, lastframe;
+ char c, *cp = modif;
+ boolean_t kernel_only = TRUE;
+ boolean_t trace_thread = FALSE;
+ //db_addr_t scp = 0;
+ int scp_offset;
+
+ while ((c = *cp++) != 0) {
+ if (c == 'u')
+ kernel_only = FALSE;
+ if (c == 't')
+ trace_thread = TRUE;
+ }
+
+ if (!have_addr) {
+ // Implement
+ } else {
+ // Implement
+ }
+ lastframe = 0;
+ //scp_offset = -get_pc_str_offset();
+ scp_offset = -4;
+
+ while (count-- && frame != 0) {
+ break;
+ // Implement
+ }
+}
diff --git a/sys/arch/arm64/arm64/disksubr.c b/sys/arch/arm64/arm64/disksubr.c
new file mode 100644
index 00000000000..6c99c2c7335
--- /dev/null
+++ b/sys/arch/arm64/arm64/disksubr.c
@@ -0,0 +1,137 @@
+/* $OpenBSD: disksubr.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */
+
+/*
+ * Copyright (c) 1996 Theo de Raadt
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/disklabel.h>
+#include <sys/disk.h>
+
+/*
+ * Attempt to read a disk label from a device
+ * using the indicated strategy routine.
+ * The label must be partly set up before this:
+ * secpercyl, secsize and anything required for a block i/o read
+ * operation in the driver's strategy/start routines
+ * must be filled in before calling us.
+ *
+ * If dos partition table requested, attempt to load it and
+ * find disklabel inside a DOS partition.
+ *
+ * We would like to check if each MBR has a valid DOSMBR_SIGNATURE, but
+ * we cannot because it doesn't always exist. So.. we assume the
+ * MBR is valid.
+ */
+int
+readdisklabel(dev_t dev, void (*strat)(struct buf *),
+ struct disklabel *lp, int spoofonly)
+{
+ struct buf *bp = NULL;
+ int error;
+
+ if ((error = initdisklabel(lp)))
+ goto done;
+
+ /* get a buffer and initialize it */
+ bp = geteblk((int)lp->d_secsize);
+ bp->b_dev = dev;
+
+ error = readdoslabel(bp, strat, lp, NULL, spoofonly);
+ if (error == 0)
+ goto done;
+
+#if defined(CD9660)
+ error = iso_disklabelspoof(dev, strat, lp);
+ if (error == 0)
+ goto done;
+#endif
+#if defined(UDF)
+ error = udf_disklabelspoof(dev, strat, lp);
+ if (error == 0)
+ goto done;
+#endif
+
+done:
+ if (bp) {
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ }
+ disk_change = 1;
+ return (error);
+}
+
+/*
+ * Write disk label back to device after modification.
+ */
+int
+writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
+{
+ daddr_t partoff = -1;
+ int error = EIO;
+ int offset;
+ struct disklabel *dlp;
+ struct buf *bp = NULL;
+
+ /* get a buffer and initialize it */
+ bp = geteblk((int)lp->d_secsize);
+ bp->b_dev = dev;
+
+ if (readdoslabel(bp, strat, lp, &partoff, 1) != 0)
+ goto done;
+
+ /* Read it in, slap the new label in, and write it back out */
+ bp->b_blkno = DL_BLKTOSEC(lp, partoff + DOS_LABELSECTOR) *
+ DL_BLKSPERSEC(lp);
+ offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR);
+ bp->b_bcount = lp->d_secsize;
+ CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
+ SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
+ (*strat)(bp);
+ if ((error = biowait(bp)) != 0)
+ goto done;
+
+ dlp = (struct disklabel *)(bp->b_data + offset);
+ *dlp = *lp;
+ CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
+ SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
+ (*strat)(bp);
+ error = biowait(bp);
+
+done:
+ if (bp) {
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ }
+ disk_change = 1;
+ return (error);
+}
diff --git a/sys/arch/arm64/arm64/exception.S b/sys/arch/arm64/arm64/exception.S
new file mode 100644
index 00000000000..5c0ffe546ad
--- /dev/null
+++ b/sys/arch/arm64/arm64/exception.S
@@ -0,0 +1,214 @@
+/* $OpenBSD: exception.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+
+#include "assym.h"
+
+ .text
+
+.macro save_registers el
+.if \el == 1
+ mov x18, sp
+ sub sp, sp, #128
+.endif
+ sub sp, sp, #(TF_SIZE + 16)
+ stp x29, x30, [sp, #(TF_SIZE)]
+ stp x28, x29, [sp, #(TF_X + 28 * 8)]
+ stp x26, x27, [sp, #(TF_X + 26 * 8)]
+ stp x24, x25, [sp, #(TF_X + 24 * 8)]
+ stp x22, x23, [sp, #(TF_X + 22 * 8)]
+ stp x20, x21, [sp, #(TF_X + 20 * 8)]
+ stp x18, x19, [sp, #(TF_X + 18 * 8)]
+ stp x16, x17, [sp, #(TF_X + 16 * 8)]
+ stp x14, x15, [sp, #(TF_X + 14 * 8)]
+ stp x12, x13, [sp, #(TF_X + 12 * 8)]
+ stp x10, x11, [sp, #(TF_X + 10 * 8)]
+ stp x8, x9, [sp, #(TF_X + 8 * 8)]
+ stp x6, x7, [sp, #(TF_X + 6 * 8)]
+ stp x4, x5, [sp, #(TF_X + 4 * 8)]
+ stp x2, x3, [sp, #(TF_X + 2 * 8)]
+ stp x0, x1, [sp, #(TF_X + 0 * 8)]
+ mrs x10, elr_el1
+ mrs x11, spsr_el1
+.if \el == 0
+ mrs x18, sp_el0
+.endif
+ mov fp, x18
+ stp x10, x11, [sp, #(TF_ELR)]
+ stp x18, lr, [sp, #(TF_SP)]
+ mrs x18, tpidr_el1
+ add x29, sp, #(TF_SIZE)
+.endm
+
+.macro restore_registers el
+.if \el == 1
+ msr daifset, #2
+ /*
+ * Disable interrupts, x18 may change in the interrupt exception
+ * handler. For EL0 exceptions, do_ast already did this.
+ */
+.endif
+ ldp x18, lr, [sp, #(TF_SP)]
+ ldp x10, x11, [sp, #(TF_ELR)]
+.if \el == 0
+ msr sp_el0, x18
+.endif
+ msr spsr_el1, x11
+ msr elr_el1, x10
+ ldp x0, x1, [sp, #(TF_X + 0 * 8)]
+ ldp x2, x3, [sp, #(TF_X + 2 * 8)]
+ ldp x4, x5, [sp, #(TF_X + 4 * 8)]
+ ldp x6, x7, [sp, #(TF_X + 6 * 8)]
+ ldp x8, x9, [sp, #(TF_X + 8 * 8)]
+ ldp x10, x11, [sp, #(TF_X + 10 * 8)]
+ ldp x12, x13, [sp, #(TF_X + 12 * 8)]
+ ldp x14, x15, [sp, #(TF_X + 14 * 8)]
+ ldp x16, x17, [sp, #(TF_X + 16 * 8)]
+.if \el == 0
+ /*
+ * We only restore the callee saved registers when returning to
+ * userland as they may have been updated by a system call or signal.
+ */
+ ldp x18, x19, [sp, #(TF_X + 18 * 8)]
+ ldp x20, x21, [sp, #(TF_X + 20 * 8)]
+ ldp x22, x23, [sp, #(TF_X + 22 * 8)]
+ ldp x24, x25, [sp, #(TF_X + 24 * 8)]
+ ldp x26, x27, [sp, #(TF_X + 26 * 8)]
+ ldp x28, x29, [sp, #(TF_X + 28 * 8)]
+.else
+ ldr x29, [sp, #(TF_X + 29 * 8)]
+.endif
+.if \el == 0
+ add sp, sp, #(TF_SIZE + 16)
+.else
+ mov sp, x18
+ mrs x18, tpidr_el1
+.endif
+.endm
+
+.macro do_ast
+ /* Disable interrupts */
+ mrs x19, daif
+1:
+ msr daifset, #2
+
+ /* Read the current thread flags */
+ mrs x18, tpidr_el1
+ ldrb w1, [x18, #CI_WANT_RESCHED]
+ /* Check if we have either bits set */
+ cmp w1, #0
+ b.eq 2f
+
+ /* Restore interrupts */
+ msr daif, x19
+
+ /* handle the ast */
+ mov x0, sp
+ bl _C_LABEL(ast)
+ b 1b
+2:
+.endm
+
+handle_el1h_sync:
+ save_registers 1
+ mov x0, sp
+ bl do_el1h_sync
+ restore_registers 1
+ eret
+
+handle_el1h_irq:
+ save_registers 1
+ mov x0, sp
+ bl arm_cpu_intr
+ restore_registers 1
+ eret
+
+handle_el1h_error:
+ brk 0xf13
+
+handle_el0_sync:
+ save_registers 0
+ mov x0, sp
+ bl do_el0_sync
+ bl _C_LABEL(vfp_enable)
+ENTRY(syscall_return)
+ do_ast
+ restore_registers 0
+ eret
+
+handle_el0_irq:
+ save_registers 0
+ bl _C_LABEL(vfp_save)
+ mov x0, sp
+ bl arm_cpu_intr
+ bl _C_LABEL(vfp_enable)
+ restore_registers 0
+ eret
+
+handle_el0_error:
+ save_registers 0
+ mov x0, sp
+ bl do_el0_error
+ brk 0xf23
+ 1: b 1b
+
+.macro vempty
+ .align 7
+ brk 0xfff
+ 1: b 1b
+.endm
+
+.macro vector name
+ .align 7
+ b handle_\name
+.endm
+
+ .align 11
+ .globl exception_vectors
+exception_vectors:
+ vempty /* Synchronous EL1t */
+ vempty /* IRQ EL1t */
+ vempty /* FIQ EL1t */
+ vempty /* Error EL1t */
+
+ vector el1h_sync /* Synchronous EL1h */
+ vector el1h_irq /* IRQ EL1h */
+ vempty /* FIQ EL1h */
+ vector el1h_error /* Error EL1h */
+
+ vector el0_sync /* Synchronous 64-bit EL0 */
+ vector el0_irq /* IRQ 64-bit EL0 */
+ vempty /* FIQ 64-bit EL0 */
+ vector el0_error /* Error 64-bit EL0 */
+
+ vempty /* Synchronous 32-bit EL0 */
+ vempty /* IRQ 32-bit EL0 */
+ vempty /* FIQ 32-bit EL0 */
+ vempty /* Error 32-bit EL0 */
+
diff --git a/sys/arch/arm64/arm64/genassym.cf b/sys/arch/arm64/arm64/genassym.cf
new file mode 100644
index 00000000000..101dd644505
--- /dev/null
+++ b/sys/arch/arm64/arm64/genassym.cf
@@ -0,0 +1,93 @@
+# $OpenBSD: genassym.cf,v 1.1 2016/12/17 23:38:33 patrick Exp $
+# $NetBSD: genassym.cf,v 1.27 2003/11/04 10:33:16 dsl Exp$
+
+# Copyright (c) 1982, 1990 The Regents of the University of California.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# William Jolitz.
+#
+# 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 the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+include <sys/param.h>
+include <sys/proc.h>
+include <sys/systm.h>
+include <sys/mbuf.h>
+include <sys/resourcevar.h>
+include <sys/device.h>
+include <sys/user.h>
+include <sys/signal.h>
+include <sys/mbuf.h>
+include <sys/socketvar.h>
+include <netinet/in.h>
+include <netinet/ip.h>
+
+include <machine/cpu.h>
+include <machine/intr.h>
+include <uvm/uvm_extern.h>
+
+include <machine/frame.h>
+struct sigframe
+member SF_SC sf_sc
+
+struct cpu_info
+member CI_CURPROC ci_curproc
+
+struct proc
+member P_STAT p_stat
+
+struct pcb
+member PCB_ONFAULT pcb_onfault
+member PCB_FLAGS pcb_flags
+member PCB_SP pcb_sp
+member PCB_PAGEDIR pcb_pagedir
+member PCB_TCB pcb_tcb
+
+struct trapframe
+member TF_X tf_x
+member TF_SP tf_sp
+member TF_ELR tf_elr
+define TF_SIZE sizeof(struct trapframe)
+
+define PCB_FPU PCB_FPU
+define SONPROC SONPROC
+
+struct cpu_info
+member CI_CURPCB ci_curpcb
+member CI_WANT_RESCHED ci_want_resched
+
+struct proc
+member P_ADDR p_addr
+
+struct switchframe
+member SF_X19 sf_x19
+member SF_X21 sf_x21
+member SF_X23 sf_x23
+member SF_X25 sf_x25
+member SF_X27 sf_x27
+member SF_X29 sf_x29
+define SWITCHFRAME_SZ sizeof(struct switchframe)
+
+define IPL_NONE IPL_NONE
diff --git a/sys/arch/arm64/arm64/intr.c b/sys/arch/arm64/arm64/intr.c
new file mode 100644
index 00000000000..86673ac5a8b
--- /dev/null
+++ b/sys/arch/arm64/arm64/intr.c
@@ -0,0 +1,629 @@
+/* $OpenBSD: intr.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2011 Dale Rahn <drahn@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/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/timetc.h>
+#include <sys/malloc.h>
+
+#include <dev/clock_subr.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/openfirm.h>
+
+uint32_t arm_intr_get_parent(int);
+
+void *arm_intr_prereg_establish_fdt(void *, int *, int, int (*)(void *),
+ void *, char *);
+void arm_intr_prereg_disestablish_fdt(void *);
+
+int arm_dflt_splraise(int);
+int arm_dflt_spllower(int);
+void arm_dflt_splx(int);
+void arm_dflt_setipl(int);
+void *arm_dflt_intr_establish(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name);
+void arm_dflt_intr_disestablish(void *cookie);
+
+void arm_dflt_intr(void *);
+void arm_cpu_intr(void *);
+
+#define SI_TO_IRQBIT(x) (1 << (x))
+uint32_t arm_smask[NIPL];
+
+struct arm_intr_func arm_intr_func = {
+ arm_dflt_splraise,
+ arm_dflt_spllower,
+ arm_dflt_splx,
+ arm_dflt_setipl,
+ arm_dflt_intr_establish,
+ arm_dflt_intr_disestablish
+};
+
+void (*arm_intr_dispatch)(void *) = arm_dflt_intr;
+
+void
+arm_cpu_intr(void *frame)
+{
+ /* XXX - change this to have irq_dispatch use function pointer */
+ (*arm_intr_dispatch)(frame);
+}
+void
+arm_dflt_intr(void *frame)
+{
+ panic("arm_dflt_intr() called");
+}
+
+
+void *arm_intr_establish(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name)
+{
+ return arm_intr_func.intr_establish(irqno, level, func, cookie, name);
+}
+void arm_intr_disestablish(void *cookie)
+{
+ arm_intr_func.intr_disestablish(cookie);
+}
+
+/*
+ * Find the interrupt parent by walking up the tree.
+ */
+uint32_t
+arm_intr_get_parent(int node)
+{
+ uint32_t phandle = 0;
+
+ while (node && !phandle) {
+ phandle = OF_getpropint(node, "interrupt-parent", 0);
+ node = OF_parent(node);
+ }
+
+ return phandle;
+}
+
+/*
+ * Interrupt pre-registration.
+ *
+ * To allow device drivers to establish interrupt handlers before all
+ * relevant interrupt controllers have been attached, we support
+ * pre-registration of interrupt handlers. For each node in the
+ * device tree that has an "interrupt-controller" property, we
+ * register a dummy interrupt controller that simply stashes away all
+ * relevant details of the interrupt handler being established.
+ * Later, when the real interrupt controller registers itself, we
+ * establush those interrupt handlers based on that information.
+ */
+
+#define MAX_INTERRUPT_CELLS 4
+
+struct intr_prereg {
+ LIST_ENTRY(intr_prereg) ip_list;
+ uint32_t ip_phandle;
+ uint32_t ip_cell[MAX_INTERRUPT_CELLS];
+
+ int ip_level;
+ int (*ip_func)(void *);
+ void *ip_arg;
+ char *ip_name;
+
+ struct interrupt_controller *ip_ic;
+ void *ip_ih;
+};
+
+LIST_HEAD(, intr_prereg) prereg_interrupts =
+ LIST_HEAD_INITIALIZER(prereg_interrupts);
+
+void *
+arm_intr_prereg_establish_fdt(void *cookie, int *cell, int level,
+ int (*func)(void *), void *arg, char *name)
+{
+ struct interrupt_controller *ic = cookie;
+ struct intr_prereg *ip;
+ int i;
+
+ ip = malloc(sizeof(struct intr_prereg), M_DEVBUF, M_ZERO | M_WAITOK);
+ ip->ip_phandle = ic->ic_phandle;
+ for (i = 0; i < ic->ic_cells; i++)
+ ip->ip_cell[i] = cell[i];
+ ip->ip_level = level;
+ ip->ip_func = func;
+ ip->ip_arg = arg;
+ ip->ip_name = name;
+ LIST_INSERT_HEAD(&prereg_interrupts, ip, ip_list);
+
+ return ip;
+}
+
+void
+arm_intr_prereg_disestablish_fdt(void *cookie)
+{
+ struct intr_prereg *ip = cookie;
+ struct interrupt_controller *ic = ip->ip_ic;
+
+ if (ip->ip_ic != NULL && ip->ip_ih != NULL)
+ ic->ic_disestablish(ip->ip_ih);
+
+ if (ip->ip_ic != NULL)
+ LIST_REMOVE(ip, ip_list);
+
+ free(ip, M_DEVBUF, sizeof(*ip));
+}
+
+void
+arm_intr_init_fdt_recurse(int node)
+{
+ struct interrupt_controller *ic;
+
+ if (OF_getproplen(node, "interrupt-controller") >= 0) {
+ ic = malloc(sizeof(struct interrupt_controller),
+ M_DEVBUF, M_ZERO | M_WAITOK);
+ ic->ic_node = node;
+ ic->ic_cookie = ic;
+ ic->ic_establish = arm_intr_prereg_establish_fdt;
+ ic->ic_disestablish = arm_intr_prereg_disestablish_fdt;
+ arm_intr_register_fdt(ic);
+ }
+
+ for (node = OF_child(node); node; node = OF_peer(node))
+ arm_intr_init_fdt_recurse(node);
+}
+
+void
+arm_intr_init_fdt(void)
+{
+ int node = OF_peer(0);
+
+ if (node)
+ arm_intr_init_fdt_recurse(node);
+}
+
+LIST_HEAD(, interrupt_controller) interrupt_controllers =
+ LIST_HEAD_INITIALIZER(interrupt_controllers);
+
+void
+arm_intr_register_fdt(struct interrupt_controller *ic)
+{
+ struct intr_prereg *ip, *tip;
+
+ ic->ic_cells = OF_getpropint(ic->ic_node, "#interrupt-cells", 0);
+ ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0);
+ if (ic->ic_cells == 0 || ic->ic_phandle == 0)
+ return;
+ KASSERT(ic->ic_cells <= MAX_INTERRUPT_CELLS);
+
+ LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list);
+
+ /* Establish pre-registered interrupt handlers. */
+ LIST_FOREACH_SAFE(ip, &prereg_interrupts, ip_list, tip) {
+ if (ip->ip_phandle != ic->ic_phandle)
+ continue;
+
+ ip->ip_ic = ic;
+ ip->ip_ih = ic->ic_establish(ic->ic_cookie, ip->ip_cell,
+ ip->ip_level, ip->ip_func, ip->ip_arg, ip->ip_name);
+ if (ip->ip_ih == NULL)
+ printf("can't establish interrupt %s\n", ip->ip_name);
+
+ LIST_REMOVE(ip, ip_list);
+ }
+}
+
+struct arm_intr_handle {
+ struct interrupt_controller *ih_ic;
+ void *ih_ih;
+};
+
+void *
+arm_intr_establish_fdt(int node, int level, int (*func)(void *),
+ void *cookie, char *name)
+{
+ return arm_intr_establish_fdt_idx(node, 0, level, func, cookie, name);
+}
+
+void *
+arm_intr_establish_fdt_idx(int node, int idx, int level, int (*func)(void *),
+ void *cookie, char *name)
+{
+ struct interrupt_controller *ic;
+ int i, len, ncells, extended = 1;
+ uint32_t *cell, *cells, phandle;
+ struct arm_intr_handle *ih;
+ void *val = NULL;
+
+ len = OF_getproplen(node, "interrupts-extended");
+ if (len <= 0) {
+ len = OF_getproplen(node, "interrupts");
+ extended = 0;
+ }
+ if (len <= 0 || (len % sizeof(uint32_t) != 0))
+ return NULL;
+
+ /* Old style. */
+ if (!extended) {
+ phandle = arm_intr_get_parent(node);
+ LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
+ if (ic->ic_phandle == phandle)
+ break;
+ }
+
+ if (ic == NULL)
+ return NULL;
+ }
+
+ cell = cells = malloc(len, M_TEMP, M_WAITOK);
+ if (extended)
+ OF_getpropintarray(node, "interrupts-extended", cells, len);
+ else
+ OF_getpropintarray(node, "interrupts", cells, len);
+ ncells = len / sizeof(uint32_t);
+
+ for (i = 0; i <= idx && ncells > 0; i++) {
+ if (extended) {
+ phandle = cell[0];
+
+ LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
+ if (ic->ic_phandle == phandle)
+ break;
+ }
+
+ if (ic == NULL)
+ break;
+
+ cell++;
+ ncells--;
+ }
+
+ if (i == idx && ncells >= ic->ic_cells && ic->ic_establish) {
+ val = ic->ic_establish(ic->ic_cookie, cell, level,
+ func, cookie, name);
+ break;
+ }
+
+ cell += ic->ic_cells;
+ ncells -= ic->ic_cells;
+ }
+
+ free(cells, M_TEMP, len);
+
+ if (val == NULL)
+ return NULL;
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
+ ih->ih_ic = ic;
+ ih->ih_ih = val;
+
+ return ih;
+}
+
+void
+arm_intr_disestablish_fdt(void *cookie)
+{
+ struct arm_intr_handle *ih = cookie;
+ struct interrupt_controller *ic = ih->ih_ic;
+
+ ic->ic_disestablish(ih->ih_ih);
+ free(ih, M_DEVBUF, sizeof(*ih));
+}
+
+/*
+ * Some interrupt controllers transparently forward interrupts to
+ * their parent. Such interrupt controllers can use this function to
+ * delegate the interrupt handler to their parent.
+ */
+void *
+arm_intr_parent_establish_fdt(void *cookie, int *cell, int level,
+ int (*func)(void *), void *arg, char *name)
+{
+ struct interrupt_controller *ic = cookie;
+ struct arm_intr_handle *ih;
+ uint32_t phandle;
+ void *val;
+
+ phandle = arm_intr_get_parent(ic->ic_node);
+ LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
+ if (ic->ic_phandle == phandle)
+ break;
+ }
+ if (ic == NULL)
+ return NULL;
+
+ val = ic->ic_establish(ic->ic_cookie, cell, level, func, arg, name);
+ if (val == NULL)
+ return NULL;
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
+ ih->ih_ic = ic;
+ ih->ih_ih = val;
+
+ return ih;
+}
+
+void
+arm_intr_parent_disestablish_fdt(void *cookie)
+{
+ struct arm_intr_handle *ih = cookie;
+ struct interrupt_controller *ic = ih->ih_ic;
+
+ ic->ic_disestablish(ih->ih_ih);
+ free(ih, M_DEVBUF, sizeof(*ih));
+}
+
+int
+arm_dflt_splraise(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int oldcpl;
+
+ oldcpl = ci->ci_cpl;
+
+ if (newcpl < oldcpl)
+ newcpl = oldcpl;
+
+ ci->ci_cpl = newcpl;
+
+ return oldcpl;
+}
+
+int
+arm_dflt_spllower(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int oldcpl;
+
+ oldcpl = ci->ci_cpl;
+
+ splx(newcpl);
+
+ return oldcpl;
+}
+
+void
+arm_dflt_splx(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+
+ if (ci->ci_ipending & arm_smask[newcpl])
+ arm_do_pending_intr(newcpl);
+ ci->ci_cpl = newcpl;
+}
+
+void
+arm_dflt_setipl(int newcpl)
+{
+ struct cpu_info *ci = curcpu();
+
+ ci->ci_cpl = newcpl;
+}
+
+void *arm_dflt_intr_establish(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name)
+{
+ panic("arm_dflt_intr_establish called");
+}
+
+void arm_dflt_intr_disestablish(void *cookie)
+{
+ panic("arm_dflt_intr_disestablish called");
+}
+
+void
+arm_do_pending_intr(int pcpl)
+{
+ struct cpu_info *ci = curcpu();
+ int oldirqstate;
+
+ oldirqstate = disable_interrupts();
+
+#define DO_SOFTINT(si, ipl) \
+ if ((ci->ci_ipending & arm_smask[pcpl]) & \
+ SI_TO_IRQBIT(si)) { \
+ ci->ci_ipending &= ~SI_TO_IRQBIT(si); \
+ arm_intr_func.setipl(ipl); \
+ restore_interrupts(oldirqstate); \
+ softintr_dispatch(si); \
+ oldirqstate = disable_interrupts(); \
+ }
+
+ do {
+ DO_SOFTINT(SIR_TTY, IPL_SOFTTTY);
+ DO_SOFTINT(SIR_NET, IPL_SOFTNET);
+ DO_SOFTINT(SIR_CLOCK, IPL_SOFTCLOCK);
+ DO_SOFTINT(SIR_SOFT, IPL_SOFT);
+ } while (ci->ci_ipending & arm_smask[pcpl]);
+
+ /* Don't use splx... we are here already! */
+ arm_intr_func.setipl(pcpl);
+ restore_interrupts(oldirqstate);
+}
+
+void arm_set_intr_handler(int (*raise)(int), int (*lower)(int),
+ void (*x)(int), void (*setipl)(int),
+ void *(*intr_establish)(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name),
+ void (*intr_disestablish)(void *cookie),
+ void (*intr_handle)(void *))
+{
+ arm_intr_func.raise = raise;
+ arm_intr_func.lower = lower;
+ arm_intr_func.x = x;
+ arm_intr_func.setipl = setipl;
+ arm_intr_func.intr_establish = intr_establish;
+ arm_intr_func.intr_disestablish = intr_disestablish;
+ arm_intr_dispatch = intr_handle;
+}
+
+void
+arm_init_smask(void)
+{
+ static int inited = 0;
+ int i;
+
+ if (inited)
+ return;
+ inited = 1;
+
+ for (i = IPL_NONE; i <= IPL_HIGH; i++) {
+ arm_smask[i] = 0;
+ if (i < IPL_SOFT)
+ arm_smask[i] |= SI_TO_IRQBIT(SIR_SOFT);
+ if (i < IPL_SOFTCLOCK)
+ arm_smask[i] |= SI_TO_IRQBIT(SIR_CLOCK);
+ if (i < IPL_SOFTNET)
+ arm_smask[i] |= SI_TO_IRQBIT(SIR_NET);
+ if (i < IPL_SOFTTTY)
+ arm_smask[i] |= SI_TO_IRQBIT(SIR_TTY);
+ }
+}
+
+/* provide functions for asm */
+#undef splraise
+#undef spllower
+#undef splx
+
+int
+splraise(int ipl)
+{
+ return arm_intr_func.raise(ipl);
+}
+
+int _spllower(int ipl); /* XXX - called from asm? */
+int
+_spllower(int ipl)
+{
+ return arm_intr_func.lower(ipl);
+}
+int
+spllower(int ipl)
+{
+ return arm_intr_func.lower(ipl);
+}
+
+void
+splx(int ipl)
+{
+ arm_intr_func.x(ipl);
+}
+
+
+#ifdef DIAGNOSTIC
+void
+arm_splassert_check(int wantipl, const char *func)
+{
+ int oldipl = curcpu()->ci_cpl;
+
+ if (oldipl < wantipl) {
+ splassert_fail(wantipl, oldipl, func);
+ /*
+ * If the splassert_ctl is set to not panic, raise the ipl
+ * in a feeble attempt to reduce damage.
+ */
+ arm_intr_func.setipl(wantipl);
+ }
+
+ if (wantipl == IPL_NONE && curcpu()->ci_idepth != 0) {
+ splassert_fail(-1, curcpu()->ci_idepth, func);
+ }
+}
+#endif
+
+void arm_dflt_delay(u_int usecs);
+
+struct {
+ void (*delay)(u_int);
+ void (*initclocks)(void);
+ void (*setstatclockrate)(int);
+ void (*mpstartclock)(void);
+} arm_clock_func = {
+ arm_dflt_delay,
+ NULL,
+ NULL,
+ NULL
+};
+
+void
+arm_clock_register(void (*initclock)(void), void (*delay)(u_int),
+ void (*statclock)(int), void(*mpstartclock)(void))
+{
+ if (arm_clock_func.initclocks)
+ return;
+
+ arm_clock_func.initclocks = initclock;
+ arm_clock_func.delay = delay;
+ arm_clock_func.setstatclockrate = statclock;
+ arm_clock_func.mpstartclock = mpstartclock;
+}
+
+
+void
+delay(u_int usec)
+{
+ arm_clock_func.delay(usec);
+}
+
+void
+cpu_initclocks(void)
+{
+ if (arm_clock_func.initclocks == NULL)
+ panic("initclocks function not initialized yet");
+
+ arm_clock_func.initclocks();
+}
+
+void
+arm_dflt_delay(u_int usecs)
+{
+ int j;
+ /* BAH - there is no good way to make this close */
+ /* but this isn't supposed to be used after the real clock attaches */
+ for (; usecs > 0; usecs--)
+ for (j = 100; j > 0; j--)
+ ;
+
+}
+
+todr_chip_handle_t todr_handle;
+
+/*
+ * resettodr:
+ *
+ * Reset the time-of-day register with the current time.
+ */
+void
+resettodr(void)
+{
+ struct timeval rtctime;
+
+ if (time_second == 1)
+ return;
+
+ microtime(&rtctime);
+
+ if (todr_handle != NULL &&
+ todr_settime(todr_handle, &rtctime) != 0)
+ printf("resettodr: failed to set time\n");
+}
+
+void
+setstatclockrate(int new)
+{
+ if (arm_clock_func.setstatclockrate == NULL) {
+ panic("arm_clock_func.setstatclockrate not intialized");
+ }
+ arm_clock_func.setstatclockrate(new);
+}
diff --git a/sys/arch/arm64/arm64/locore.S b/sys/arch/arm64/arm64/locore.S
new file mode 100644
index 00000000000..9fb7f252631
--- /dev/null
+++ b/sys/arch/arm64/arm64/locore.S
@@ -0,0 +1,652 @@
+/* $OpenBSD: locore.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2012-2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "assym.h"
+#include <sys/syscall.h>
+#include <machine/asm.h>
+#include <machine/armreg.h>
+#include <machine/hypervisor.h>
+#include <machine/param.h>
+#include <machine/pte.h>
+
+#define VIRT_BITS 39
+
+#define DEVICE_MEM 0
+#define NORMAL_UNCACHED 1
+#define NORMAL_MEM 2
+
+/*
+ * We assume:
+ * MMU on with an identity map, or off
+ * D-Cache: off
+ * I-Cache: on or off
+ * We are loaded at a 2MiB aligned address
+ */
+
+#define INIT_STACK_SIZE (PAGE_SIZE * 4)
+
+ .text
+ .globl _start
+_start:
+ mov x21, x0
+ mov x22, x1
+ mov x23, x2
+
+ /* Store symbol value. */
+ adr x0, .Lesym
+ str x21, [x0]
+
+ /* Drop to EL1 */
+ bl drop_to_el1
+
+ /*
+ * Disable the MMU. We may have entered the kernel with it on and
+ * will need to update the tables later. If this has been set up
+ * with anything other than a VA == PA map then this will fail,
+ * but in this case the code to find where we are running from
+ * would have also failed.
+ */
+ dsb sy
+ mrs x2, sctlr_el1
+ bic x2, x2, SCTLR_M
+ msr sctlr_el1, x2
+ isb
+
+
+ /* Get the virt -> phys offset */
+ bl get_virt_delta
+
+ /*
+ * At this point:
+ * x29 = PA - VA
+ * x28 = Our physical load address
+ */
+
+ /* Create the page tables */
+ bl create_pagetables
+
+
+ mrs x0, DCZID_EL0
+ tbnz x0, 4, 1f
+ mov x1, #1
+ and x0, x0, 0xf
+ lsl x1, x1, x0
+ ldr x0, =dczva_line_size
+ // adjust virtual address to physical
+ sub x0, x0, x29
+
+ str x1, [x0]
+1:
+ /*
+ * At this point:
+ * x27 = TTBR0 table
+ * x26 = TTBR1 table
+ */
+
+
+ /* Enable the mmu */
+ bl start_mmu
+
+ /* Jump to the virtual address space */
+ ldr x15, .Lvirtdone
+ br x15
+
+.Linitstack:
+ .xword initstack
+.Linitstack_end:
+ .xword initstack_end
+virtdone:
+ /* Set up the stack */
+ adr x25, .Linitstack_end
+ ldr x25, [x25]
+ mov sp, x25
+ mov x8, #TRAPFRAME_SIZEOF
+ sub x8, x8, (STACKALIGNBYTES)
+ and x8, x8, ~(STACKALIGNBYTES)
+
+ // pass base of kernel stack as proc0
+ adr x25, .Linitstack
+ ldr x25, [x25]
+
+ sub sp, sp, x8
+
+ /* Zero the BSS */
+ ldr x15, .Lbss
+ ldr x14, .Lend
+1:
+ str xzr, [x15], #8
+ cmp x15, x14
+ b.lo 1b
+
+ /* Backup the module pointer */
+ mov x1, x0
+
+ /* Make the page table base a virtual address */
+ sub x26, x26, x29
+
+ // XXX - shouldn't this be 8 * 5 (struct grew from 4 -> 5)
+ sub sp, sp, #(64 * 4)
+ mov x0, sp
+
+ /* Negate the delta so it is VA -> PA */
+ neg x29, x29
+
+ str x1, [x0] /* modulep */
+ str x26, [x0, 8] /* kern_l1pt */
+ str x29, [x0, 16] /* kern_delta */
+ str x25, [x0, 24] /* kern_stack */
+ str x21, [x0, 32] /* ? (x0 arg on boot) */
+ str x22, [x0, 40] /* ? (x1 arg on boot) */
+ str x23, [x0, 48] /* fdt (x2 arg on boot) */
+
+ /* trace back starts here */
+ mov fp, #0
+ /* Branch to C code */
+ bl initarm
+ bl _C_LABEL(main)
+
+ /* We should not get here */
+ brk 0
+
+ .align 3
+.Lvirtdone:
+ .quad virtdone
+.Lbss:
+ .quad __bss_start
+.Lstart:
+ .quad _start
+.Lend:
+ .quad _end
+.Lcpu_info_primary:
+ .quad _C_LABEL(cpu_info_primary)
+
+/*
+ * If we are started in EL2, configure the required hypervisor
+ * registers and drop to EL1.
+ */
+drop_to_el1:
+ mrs x1, CurrentEL
+ lsr x1, x1, #2
+ cmp x1, #0x2
+ b.eq 1f
+ ret
+1:
+ /* Configure the Hypervisor */
+ mov x2, #(HCR_RW)
+ msr hcr_el2, x2
+
+ /* Load the Virtualization Process ID Register */
+ mrs x2, midr_el1
+ msr vpidr_el2, x2
+
+ /* Load the Virtualization Multiprocess ID Register */
+ mrs x2, mpidr_el1
+ msr vmpidr_el2, x2
+
+ /* Set the bits that need to be 1 in sctlr_el1 */
+ ldr x2, .Lsctlr_res1
+ msr sctlr_el1, x2
+
+ /* Don't trap to EL2 for exceptions */
+ mov x2, #CPTR_RES1
+ msr cptr_el2, x2
+
+ /* Don't trap to EL2 for CP15 traps */
+ msr hstr_el2, xzr
+
+ /* Hypervisor trap functions */
+ adr x2, hyp_vectors
+ msr vbar_el2, x2
+
+ mov x2, #(PSR_F | PSR_I | PSR_A | PSR_D | PSR_M_EL1h)
+ msr spsr_el2, x2
+
+ /* Configure GICv3 CPU interface */
+ mrs x2, id_aa64pfr0_el1
+ /* Extract GIC bits from the register */
+ ubfx x2, x2, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_BITS
+ /* GIC[3:0] == 0001 - GIC CPU interface via special regs. supported */
+ cmp x2, #(ID_AA64PFR0_GIC_CPUIF_EN >> ID_AA64PFR0_GIC_SHIFT)
+ b.ne 2f
+
+ mrs x2, icc_sre_el2
+ orr x2, x2, #ICC_SRE_EL2_EN /* Enable access from insecure EL1 */
+ msr icc_sre_el2, x2
+ isb
+2:
+
+ /* Set the address to return to our return address */
+ msr elr_el2, x30
+
+ eret
+
+ .align 3
+.Lsctlr_res1:
+ .quad SCTLR_RES1
+
+#define VECT_EMPTY \
+ .align 7; \
+ 1: b 1b
+
+ .align 11
+hyp_vectors:
+ VECT_EMPTY /* Synchronous EL2t */
+ VECT_EMPTY /* IRQ EL2t */
+ VECT_EMPTY /* FIQ EL2t */
+ VECT_EMPTY /* Error EL2t */
+
+ VECT_EMPTY /* Synchronous EL2h */
+ VECT_EMPTY /* IRQ EL2h */
+ VECT_EMPTY /* FIQ EL2h */
+ VECT_EMPTY /* Error EL2h */
+
+ VECT_EMPTY /* Synchronous 64-bit EL1 */
+ VECT_EMPTY /* IRQ 64-bit EL1 */
+ VECT_EMPTY /* FIQ 64-bit EL1 */
+ VECT_EMPTY /* Error 64-bit EL1 */
+
+ VECT_EMPTY /* Synchronous 32-bit EL1 */
+ VECT_EMPTY /* IRQ 32-bit EL1 */
+ VECT_EMPTY /* FIQ 32-bit EL1 */
+ VECT_EMPTY /* Error 32-bit EL1 */
+
+/*
+ * Get the delta between the physical address we were loaded to and the
+ * virtual address we expect to run from. This is used when building the
+ * initial page table.
+ */
+ .globl get_virt_delta
+get_virt_delta:
+ /* Load the physical address of virt_map */
+ adr x28, virt_map
+ /* Load the virtual address of virt_map stored in virt_map */
+ ldr x29, [x28]
+ /* Find PA - VA as PA' = VA' - VA + PA = VA' + (PA - VA) = VA' + x29 */
+ sub x29, x29, x28
+ and x28, x28, #~0x0003ffff // should be 2MB?
+
+ ret
+
+ .align 3
+virt_map:
+ .quad virt_map
+
+/*
+ * This builds the page tables containing the identity map, and the kernel
+ * virtual map.
+ *
+ * It relys on:
+ * We were loaded to an address that is on a 2MiB boundary
+ * All the memory must not cross a 1GiB boundaty
+ * x28 contains the physical address we were loaded from
+ *
+ * There are 3 pages before that address for the page tables
+ * These pages are allocated aligned in .data
+ * The pages used are:
+ * - The identity (PA = VA) table (TTBR0)
+ * - The Kernel L1 table (TTBR1)
+ * - The PA == VA L2 table for kernel
+ */
+.Lpagetable:
+ .xword pagetable
+.Lpagetable_end:
+ .xword pagetable_end
+
+.Lesym:
+ .xword esym
+
+create_pagetables:
+ /* Save the Link register */
+ mov x5, x30
+
+ /* Clean the page table */
+ adr x6, .Lpagetable
+ ldr x6, [x6]
+ sub x6, x6, x29 // VA -> PA
+ mov x26, x6
+ adr x27, .Lpagetable_end
+ ldr x27, [x27]
+ sub x27, x27, x29 // VA -> PA
+1:
+ stp xzr, xzr, [x6], #16
+ stp xzr, xzr, [x6], #16
+ stp xzr, xzr, [x6], #16
+ stp xzr, xzr, [x6], #16
+ cmp x6, x27
+ b.lo 1b
+
+ /*
+ * Build the TTBR1 maps.
+ */
+
+ /* Find the size of the kernel */
+ ldr x6, .Lstart
+ sub x6, x6, x29
+
+ /* End is the symbol address */
+ adr x7, .Lesym
+ ldr x7, [x7]
+ sub x7, x7, x29
+
+ /* Find the end - begin */
+ sub x8, x7, x6
+ /* Get the number of l2 pages to allocate, rounded down */
+ lsr x10, x8, #(L2_SHIFT)
+ /* Add 4 MiB for any rounding above and the module data */
+ add x10, x10, #2
+
+ /* Create the kernel space L2 table */
+ mov x6, x26 // pagetable:
+ mov x7, #NORMAL_MEM
+ add x8, x28, x29
+ mov x9, x28
+ bl build_block_pagetable
+
+ /* Move to the l1 table */
+ add x26, x26, #PAGE_SIZE*2 // pagetable_l1_ttbr1:
+
+ /* Link the l1 -> l2 table */
+ mov x9, x6
+ mov x6, x26
+ bl link_l1_pagetable
+
+
+ /*
+ * Build the TTBR0 maps.
+ */
+ add x27, x26, #PAGE_SIZE *2 // pagetable_l1_ttbr0:
+
+#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
+ /* Create a table for the UART */
+ mov x6, x27 /* The initial page table */
+ mov x7, #DEVICE_MEM
+ mov x8, #(SOCDEV_VA) /* VA start */
+ mov x9, #(SOCDEV_PA) /* PA start */
+ bl build_section_pagetable
+#endif
+
+ /* Create the VA = PA map */
+ mov x6, x27 /* The initial page table */
+ mov x7, #NORMAL_MEM // #NORMAL
+ mov x9, x27
+ mov x8, x9 /* VA start (== PA start) */
+ bl build_section_pagetable
+
+ /* Restore the Link register */
+ mov x30, x5
+ ret
+
+/*
+ * Builds a 1 GiB page table entry
+ * x6 = L1 table
+ * x7 = Type (0 = Device, 1 = Normal)
+ * x8 = VA start
+ * x9 = PA start (trashed)
+ * x11, x12 and x13 are trashed
+ */
+build_section_pagetable:
+ /*
+ * Build the L1 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L1_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L1 block entry */
+ lsl x12, x7, #2
+ orr x12, x12, #L1_BLOCK
+ orr x12, x12, #(ATTR_AF)
+
+ /* Only use the output address bits */
+ lsr x9, x9, #L1_SHIFT
+ orr x12, x12, x9, lsl #L1_SHIFT
+
+ /* Store the entry */
+ str x12, [x6, x11, lsl #3]
+
+ ret
+
+/*
+ * Builds an L1 -> L2 table descriptor
+ *
+ * This is a link for a 1GiB block of memory with up to 2MiB regions mapped
+ * within it by build_block_pagetable.
+ *
+ * x6 = L1 table
+ * x8 = Virtual Address
+ * x9 = L2 PA (trashed)
+ * x11, x12 and x13 are trashed
+ */
+.global link_l1_pagetable
+link_l1_pagetable:
+ /*
+ * Link an L1 -> L2 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L1_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L1 block entry */
+ mov x12, #L1_TABLE
+
+ /* Only use the output address bits */
+ lsr x9, x9, #12
+ orr x12, x12, x9, lsl #12
+
+ /* Store the entry */
+ str x12, [x6, x11, lsl #3]
+
+ ret
+
+/*
+ * Builds count 2 MiB page table entry
+ * x6 = L2 table
+ * x7 = Type (0 = Device, 1 = Normal)
+ * x8 = VA start
+ * x9 = PA start (trashed)
+ * x10 = Entry count (TODO)
+ * x11, x12 and x13 are trashed
+ */
+.global build_block_pagetable
+build_block_pagetable:
+ /*
+ * Build the L2 table entry.
+ */
+ /* Find the table index */
+ lsr x11, x8, #L2_SHIFT
+ and x11, x11, #Ln_ADDR_MASK
+
+ /* Build the L2 block entry */
+ lsl x12, x7, #2
+ orr x12, x12, #L2_BLOCK
+ orr x12, x12, #(ATTR_AF)
+
+ /* Only use the output address bits */
+ lsr x9, x9, #L2_SHIFT
+
+ /* Set the physical address for this virtual address */
+1: orr x12, x12, x9, lsl #L2_SHIFT
+
+ /* Store the entry */
+ str x12, [x6, x11, lsl #3]
+
+ /* Clear the address bits */
+ and x12, x12, #ATTR_MASK_L
+
+ sub x10, x10, #1
+ add x11, x11, #1
+ add x9, x9, #1
+ cbnz x10, 1b
+
+2:
+ ret
+
+start_mmu:
+ dsb sy
+
+ /* Load the exception vectors */
+ ldr x2, =exception_vectors
+ msr vbar_el1, x2
+
+ /* Load ttbr0 and ttbr1 */
+ msr ttbr0_el1, x27
+ msr ttbr1_el1, x26
+ isb
+
+ /* Clear the Monitor Debug System control register */
+ msr mdscr_el1, xzr
+
+ /* Invalidate the TLB */
+ tlbi vmalle1is
+
+ ldr x2, mair
+ msr mair_el1, x2
+
+ /* Setup TCR according to PARange bits from ID_AA64MMFR0_EL1 */
+ ldr x2, tcr
+ mrs x3, id_aa64mmfr0_el1
+ bfi x2, x3, #32, #3
+ msr tcr_el1, x2
+
+ /* Setup SCTLR */
+ ldr x2, sctlr_set
+ ldr x3, sctlr_clear
+ mrs x1, sctlr_el1
+ bic x1, x1, x3 /* Clear the required bits */
+ orr x1, x1, x2 /* Set the required bits */
+ msr sctlr_el1, x1
+ isb
+
+ ret
+ .globl switch_mmu_kernel
+switch_mmu_kernel:
+ dsb sy
+ /* Invalidate the TLB */
+ tlbi vmalle1is
+ /* Load ttbr1 (kernel) */
+ msr ttbr1_el1, x0
+ isb
+ ret
+
+
+
+ .align 3
+mair:
+ /* Device Normal, no cache Normal, write-back */
+ .quad MAIR_ATTR(0x00, 0) | MAIR_ATTR(0x44, 1) | MAIR_ATTR(0xff, 2)
+tcr:
+ .quad (TCR_TxSZ(64 - VIRT_BITS) | TCR_ASID_16 | TCR_TG1_4K | \
+ TCR_SH0(3)|TCR_SH1(3)|TCR_ORGNx(1)|TCR_IRGNx(1))
+sctlr_set:
+ /* Bits to set */
+ .quad (SCTLR_UCI | SCTLR_nTWE | SCTLR_nTWI | SCTLR_UCT | SCTLR_DZE | \
+ SCTLR_I | SCTLR_SED | SCTLR_C | SCTLR_M)
+sctlr_clear:
+ /* Bits to clear */
+ .quad (SCTLR_EE | SCTLR_EOE | SCTLR_WXN | SCTLR_UMA | SCTLR_ITD | \
+ SCTLR_THEE | SCTLR_CP15BEN | SCTLR_SA0 | SCTLR_SA | SCTLR_A)
+
+ .globl abort
+abort:
+ b abort
+
+ // First entries in data must be esym
+ // so that bootloader can find them easily.
+ .data
+ .global _C_LABEL(esym)
+_C_LABEL(esym): .xword _C_LABEL(end)
+ .global _C_LABEL(dczva_line_size)
+_C_LABEL(dczva_line_size): .xword 0
+
+ //.section .init_pagetable
+data_align_pad:
+ .space 32
+ .align 12 /* 4KiB aligned */
+ /*
+ * 3 initial tables (in the following order):
+ * L2 for kernel (High addresses)
+ * L1 for kernel
+ * L1 for user (Low addresses)
+ */
+ .globl pagetable
+pagetable:
+ .space PAGE_SIZE * 2 // allocate 2 pages for pmapvp2
+pagetable_l1_ttbr1:
+ .space PAGE_SIZE * 2 // allocate 2 pages for pmapvp1
+pagetable_l1_ttbr0:
+ .space PAGE_SIZE * 2 // allocate 2 pages, reused later in pmap
+pagetable_end:
+
+ .text
+#if 0
+ .globl init_pt_va
+init_pt_va:
+ .quad pagetable /* XXX: Keep page tables VA */
+#endif
+
+ .bss
+ .align 4
+ .globl initstack
+initstack:
+ .space USPACE
+initstack_end:
+
+ .text
+ENTRY(sigcode)
+ mov x0, sp
+ add x0, x0, #SF_SC
+
+1:
+ mov x8, #SYS_sigreturn
+ svc 0
+ .globl _C_LABEL(sigcoderet)
+_C_LABEL(sigcoderet):
+
+ /* sigreturn failed, exit */
+ mov x8, #SYS_exit
+ svc 0
+
+ b 1b
+END(sigcode)
+ /* This may be copied to the stack, keep it 16-byte aligned */
+ .align 3
+ .global _C_LABEL(esigcode)
+_C_LABEL(esigcode):
+
+ .globl sigfill
+sigfill:
+ .word 0xa000f7f0 /* FIXME: illegal on all cpus? */
+esigfill:
+
+ .data
+ .globl sigfillsiz
+sigfillsiz:
+ .word esigfill - sigfill
+
+ .text
diff --git a/sys/arch/arm64/arm64/machdep.c b/sys/arch/arm64/arm64/machdep.c
new file mode 100644
index 00000000000..8792c1fac6d
--- /dev/null
+++ b/sys/arch/arm64/arm64/machdep.c
@@ -0,0 +1,1106 @@
+/* $OpenBSD: machdep.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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/types.h>
+#include <sys/param.h>
+#include <sys/timetc.h>
+#include <sys/sched.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/reboot.h>
+#include <sys/mount.h>
+#include <sys/exec.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/kcore.h>
+#include <sys/core.h>
+#include <sys/msgbuf.h>
+#include <sys/buf.h>
+#include <sys/termios.h>
+
+#include <net/if.h>
+#include <uvm/uvm.h>
+#include <dev/cons.h>
+#include <dev/clock_subr.h>
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+#include <machine/param.h>
+#include <machine/kcore.h>
+#include <machine/bootconfig.h>
+#include <machine/bus.h>
+#include <arm64/arm64/arm64var.h>
+
+char *boot_args = NULL;
+char *boot_file = "";
+
+extern uint64_t esym;
+
+int comcnspeed;
+int comcnmode;
+
+int stdout_node = 0;
+
+void (*cpuresetfn)(void);
+void (*powerdownfn)(void);
+
+int cold = 1;
+
+struct vm_map *exec_map = NULL;
+struct vm_map *phys_map = NULL;
+
+int physmem;
+
+struct consdev *cn_tab;
+
+caddr_t msgbufaddr;
+paddr_t msgbufphys;
+
+struct user *proc0paddr;
+
+struct uvm_constraint_range dma_constraint = { 0x0, (paddr_t)-1 };
+struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
+
+/* the following is used externally (sysctl_hw) */
+char machine[] = MACHINE; /* from <machine/param.h> */
+char cpu_model[] = "arm64"; // XXX FIX
+extern todr_chip_handle_t todr_handle;
+
+int safepri = 0;
+
+struct cpu_info cpu_info_primary;
+struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary };
+
+/*
+ * inittodr:
+ *
+ * Initialize time from the time-of-day register.
+ */
+#define MINYEAR 2003 /* minimum plausible year */
+void
+inittodr(time_t base)
+{
+ time_t deltat;
+ struct timeval rtctime;
+ struct timespec ts;
+ int badbase;
+
+ if (base < (MINYEAR - 1970) * SECYR) {
+ printf("WARNING: preposterous time in file system\n");
+ /* read the system clock anyway */
+ base = (MINYEAR - 1970) * SECYR;
+ badbase = 1;
+ } else
+ badbase = 0;
+
+ if (todr_handle == NULL ||
+ todr_gettime(todr_handle, &rtctime) != 0 ||
+ rtctime.tv_sec == 0) {
+ /*
+ * Believe the time in the file system for lack of
+ * anything better, resetting the TODR.
+ */
+ rtctime.tv_sec = base;
+ rtctime.tv_usec = 0;
+ if (todr_handle != NULL && !badbase) {
+ printf("WARNING: preposterous clock chip time\n");
+ resettodr();
+ }
+ ts.tv_sec = rtctime.tv_sec;
+ ts.tv_nsec = rtctime.tv_usec * 1000;
+ tc_setclock(&ts);
+ goto bad;
+ } else {
+ ts.tv_sec = rtctime.tv_sec;
+ ts.tv_nsec = rtctime.tv_usec * 1000;
+ tc_setclock(&ts);
+ }
+
+ if (!badbase) {
+ /*
+ * See if we gained/lost two or more days; if
+ * so, assume something is amiss.
+ */
+ deltat = rtctime.tv_sec - base;
+ if (deltat < 0)
+ deltat = -deltat;
+ if (deltat < 2 * SECDAY)
+ return; /* all is well */
+ printf("WARNING: clock %s %ld days\n",
+ rtctime.tv_sec < base ? "lost" : "gained",
+ (long)deltat / SECDAY);
+ }
+ bad:
+ printf("WARNING: CHECK AND RESET THE DATE!\n");
+}
+
+void *
+fdt_find_cons(const char *name)
+{
+ char *alias = "serial0";
+ char buf[128];
+ char *stdout = NULL;
+ char *p;
+ void *node;
+
+ /* First check if "stdout-path" is set. */
+ node = fdt_find_node("/chosen");
+ if (node) {
+ if (fdt_node_property(node, "stdout-path", &stdout) > 0) {
+ if (strchr(stdout, ':') != NULL) {
+ strlcpy(buf, stdout, sizeof(buf));
+ if ((p = strchr(buf, ':')) != NULL)
+ *p = '\0';
+ stdout = buf;
+ }
+ if (stdout[0] != '/') {
+ /* It's an alias. */
+ alias = stdout;
+ stdout = NULL;
+ }
+ }
+ }
+
+ /* Perform alias lookup if necessary. */
+ if (stdout == NULL) {
+ node = fdt_find_node("/aliases");
+ if (node)
+ fdt_node_property(node, alias, &stdout);
+ }
+
+ /* Lookup the physical address of the interface. */
+ if (stdout) {
+ node = fdt_find_node(stdout);
+ if (node && fdt_is_compatible(node, name)) {
+ stdout_node = OF_finddevice(stdout);
+ return (node);
+ }
+ }
+
+ return (NULL);
+}
+
+extern void com_fdt_init_cons(void);
+extern void pluart_init_cons(void);
+void
+consinit()
+{
+ static int consinit_called = 0;
+
+ if (consinit_called != 0)
+ return;
+
+ consinit_called = 1;
+
+ com_fdt_init_cons();
+ pluart_init_cons();
+}
+
+void
+cpu_idle_enter()
+{
+}
+
+void
+cpu_idle_cycle()
+{
+ restore_daif(0x0); // enable interrupts
+ __asm volatile("wfi");
+}
+
+void
+cpu_idle_leave()
+{
+}
+
+
+// XXX what? - not really used
+struct trapframe proc0tf;
+void
+cpu_startup()
+{
+
+ u_int loop;
+ paddr_t minaddr;
+ paddr_t maxaddr;
+
+ proc0.p_addr = proc0paddr;
+
+
+ /*
+ * Initialize error message buffer (at end of core).
+ */
+
+ /* msgbufphys was setup during the secondary boot strap */
+ for (loop = 0; loop < atop(MSGBUFSIZE); ++loop)
+ pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE,
+ msgbufphys + loop * PAGE_SIZE, PROT_READ | PROT_WRITE);
+ pmap_update(pmap_kernel());
+ initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE));
+
+ /*
+ * Identify ourselves for the msgbuf (everything printed earlier will
+ * not be buffered).
+ */
+ printf("%s", version);
+
+ printf("real mem = %lu (%luMB)\n", ptoa(physmem),
+ ptoa(physmem)/1024/1024);
+
+ /*
+ * Allocate a submap for exec arguments. This map effectively
+ * limits the number of processes exec'ing at any time.
+ */
+ minaddr = vm_map_min(kernel_map);
+ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
+ 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
+
+
+ /*
+ * Allocate a submap for physio
+ */
+ phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, 0, FALSE, NULL);
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
+ ptoa(uvmexp.free)/1024/1024);
+
+ curpcb = &proc0.p_addr->u_pcb;
+ curpcb->pcb_flags = 0;
+ curpcb->pcb_tf = &proc0tf;
+}
+
+/*
+ * machine dependent system variables.
+ */
+
+int
+cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
+ int *name;
+ u_int namelen;
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+ struct proc *p;
+{
+ /* all sysctl names at this level are terminal */
+ if (namelen != 1)
+ return (ENOTDIR); /* overloaded */
+
+ switch (name[0]) {
+ // none supported currently
+ default:
+ return (EOPNOTSUPP);
+ }
+ /* NOTREACHED */
+}
+
+void bootsync(int);
+void dumpsys(void);
+
+/*
+ * void boot(int howto, char *bootstr)
+ *
+ * Reboots the system
+ *
+ * Deal with any syncing, unmounting, dumping and shutdown hooks,
+ * then reset the CPU.
+ */
+void
+boot(int howto)
+{
+#ifdef DIAGNOSTIC
+ /* info */
+ printf("boot: howto=%08x curproc=%p\n", howto, curproc);
+#endif
+
+ /*
+ * If we are still cold then hit the air brakes
+ * and crash to earth fast
+ */
+ if (cold) {
+ if (!TAILQ_EMPTY(&alldevs))
+ config_suspend(TAILQ_FIRST(&alldevs), DVACT_POWERDOWN);
+ if ((howto & (RB_HALT | RB_USERREQ)) != RB_USERREQ) {
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ }
+ printf("rebooting...\n");
+ delay(500000);
+ if (cpuresetfn)
+ (*cpuresetfn)();
+ printf("reboot failed; spinning\n");
+ while(1);
+ /*NOTREACHED*/
+ }
+
+ /* Disable console buffering */
+/* cnpollc(1);*/
+
+ /*
+ * If RB_NOSYNC was not specified sync the discs.
+ * Note: Unless cold is set to 1 here, syslogd will die during the
+ * unmount. It looks like syslogd is getting woken up only to find
+ * that it cannot page part of the binary in as the filesystem has
+ * been unmounted.
+ */
+ if (!(howto & RB_NOSYNC))
+ bootsync(howto);
+
+ if_downall();
+
+ uvm_shutdown();
+
+ /* Say NO to interrupts */
+ splhigh();
+
+ /* Do a dump if requested. */
+ if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
+ dumpsys();
+
+ /* Run any shutdown hooks */
+ if (!TAILQ_EMPTY(&alldevs))
+ config_suspend(TAILQ_FIRST(&alldevs), DVACT_POWERDOWN);
+
+ /* Make sure IRQ's are disabled */
+ // FIXME
+
+ if (howto & RB_HALT) {
+ if (howto & RB_POWERDOWN) {
+
+ printf("\nAttempting to power down...\n");
+ delay(500000);
+ if (powerdownfn)
+ (*powerdownfn)();
+ }
+
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ }
+
+ printf("rebooting...\n");
+ delay(500000);
+ if (cpuresetfn)
+ (*cpuresetfn)();
+ printf("reboot failed; spinning\n");
+ while(1);
+ /*NOTREACHED*/
+}
+
+/* Sync the discs and unmount the filesystems */
+
+void
+bootsync(int howto)
+{
+ static int bootsyncdone = 0;
+
+ if (bootsyncdone) return;
+
+ bootsyncdone = 1;
+
+#if 0
+ /* Make sure we can still manage to do things */
+ if (__get_daif() & I_bit) {
+ /*
+ * If we get here then boot has been called without RB_NOSYNC
+ * and interrupts were disabled. This means the boot() call
+ * did not come from a user process e.g. shutdown, but must
+ * have come from somewhere in the kernel.
+ */
+ IRQenable;
+ printf("Warning IRQ's disabled during boot()\n");
+ }
+#endif
+
+ vfs_shutdown();
+
+ /*
+ * If we've been adjusting the clock, the todr
+ * will be out of synch; adjust it now unless
+ * the system has been sitting in ddb.
+ */
+ if ((howto & RB_TIMEBAD) == 0) {
+ resettodr();
+ } else {
+ printf("WARNING: not updating battery clock\n");
+ }
+}
+
+void
+setregs(struct proc *p, struct exec_package *pack, u_long stack,
+ register_t *retval)
+{
+ struct trapframe *tf;
+
+ tf = p->p_addr->u_pcb.pcb_tf;
+
+ memset (tf,0, sizeof(*tf));
+ tf->tf_sp = stack;
+ tf->tf_lr = pack->ep_entry;
+ tf->tf_elr = pack->ep_entry; /* ??? */
+ tf->tf_spsr = PSR_M_EL0t;
+}
+
+void
+need_resched(struct cpu_info *ci)
+{
+ ci->ci_want_resched = 1;
+
+ /* There's a risk we'll be called before the idle threads start */
+ if (ci->ci_curproc) {
+ aston(ci->ci_curproc);
+ //cpu_kick(ci); /* multiprocessor only ?? */
+ }
+}
+
+int cpu_dumpsize(void);
+u_long cpu_dump_mempagecnt(void);
+
+paddr_t dumpmem_paddr;
+vaddr_t dumpmem_vaddr;
+psize_t dumpmem_sz;
+
+/*
+ * These variables are needed by /sbin/savecore
+ */
+u_long dumpmag = 0x8fca0101; /* magic number */
+int dumpsize = 0; /* pages */
+long dumplo = 0; /* blocks */
+
+/*
+ * cpu_dump: dump the machine-dependent kernel core dump headers.
+ */
+int
+cpu_dump(void)
+{
+ int (*dump)(dev_t, daddr_t, caddr_t, size_t);
+ char buf[dbtob(1)];
+ kcore_seg_t *segp;
+ cpu_kcore_hdr_t *cpuhdrp;
+ phys_ram_seg_t *memsegp;
+ caddr_t va;
+ // int i;
+
+ dump = bdevsw[major(dumpdev)].d_dump;
+
+ memset(buf, 0, sizeof buf);
+ segp = (kcore_seg_t *)buf;
+ cpuhdrp = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(*segp))];
+ memsegp = (phys_ram_seg_t *)&buf[ALIGN(sizeof(*segp)) +
+ ALIGN(sizeof(*cpuhdrp))];
+
+ /*
+ * Generate a segment header.
+ */
+ CORE_SETMAGIC(*segp, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
+ segp->c_size = dbtob(1) - ALIGN(sizeof(*segp));
+
+ /*
+ * Add the machine-dependent header info.
+ */
+ cpuhdrp->kernelbase = KERNEL_BASE;
+ cpuhdrp->kerneloffs = 0; // XXX
+ cpuhdrp->staticsize = 0; // XXX
+ cpuhdrp->pmap_kernel_l1 = 0; // XXX
+ cpuhdrp->pmap_kernel_l1 = 0; // XXX
+
+#if 0
+ /*
+ * Fill in the memory segment descriptors.
+ */
+ for (i = 0; i < mem_cluster_cnt; i++) {
+ memsegp[i].start = mem_clusters[i].start;
+ memsegp[i].size = mem_clusters[i].size & PMAP_PA_MASK;
+ }
+
+ /*
+ * If we have dump memory then assume the kernel stack is in high
+ * memory and bounce
+ */
+ if (dumpmem_vaddr != 0) {
+ memcpy((char *)dumpmem_vaddr, buf, sizeof(buf));
+ va = (caddr_t)dumpmem_vaddr;
+ } else {
+ va = (caddr_t)buf;
+ }
+#endif
+ return (dump(dumpdev, dumplo, va, dbtob(1)));
+}
+
+
+/*
+ * This is called by main to set dumplo and dumpsize.
+ * Dumps always skip the first PAGE_SIZE of disk space
+ * in case there might be a disk label stored there.
+ * If there is extra space, put dump at the end to
+ * reduce the chance that swapping trashes it.
+ */
+void
+dumpconf(void)
+{
+ int nblks, dumpblks; /* size of dump area */
+
+ if (dumpdev == NODEV ||
+ (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
+ return;
+ if (nblks <= ctod(1))
+ return;
+
+ dumpblks = cpu_dumpsize();
+ if (dumpblks < 0)
+ return;
+ dumpblks += ctod(cpu_dump_mempagecnt());
+
+ /* If dump won't fit (incl. room for possible label), punt. */
+ if (dumpblks > (nblks - ctod(1)))
+ return;
+
+ /* Put dump at end of partition */
+ dumplo = nblks - dumpblks;
+
+ /* dumpsize is in page units, and doesn't include headers. */
+ dumpsize = cpu_dump_mempagecnt();
+}
+
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+#define BYTES_PER_DUMP MAXPHYS /* must be a multiple of pagesize */
+
+void
+dumpsys(void)
+{
+ u_long totalbytesleft, bytes, i, n, memseg;
+ u_long maddr;
+ daddr_t blkno;
+ void *va;
+ int (*dump)(dev_t, daddr_t, caddr_t, size_t);
+ int error;
+
+ /* Save registers. */
+ // XXX
+ //savectx(&dumppcb);
+
+ if (dumpdev == NODEV)
+ return;
+
+ /*
+ * For dumps during autoconfiguration,
+ * if dump device has already configured...
+ */
+ if (dumpsize == 0)
+ dumpconf();
+ if (dumplo <= 0 || dumpsize == 0) {
+ printf("\ndump to dev %u,%u not possible\n", major(dumpdev),
+ minor(dumpdev));
+ return;
+ }
+ printf("\ndumping to dev %u,%u offset %ld\n", major(dumpdev),
+ minor(dumpdev), dumplo);
+
+#ifdef UVM_SWAP_ENCRYPT
+ uvm_swap_finicrypt_all();
+#endif
+
+ error = (*bdevsw[major(dumpdev)].d_psize)(dumpdev);
+ printf("dump ");
+ if (error == -1) {
+ printf("area unavailable\n");
+ return;
+ }
+
+ if ((error = cpu_dump()) != 0)
+ goto err;
+
+ totalbytesleft = ptoa(cpu_dump_mempagecnt());
+ blkno = dumplo + cpu_dumpsize();
+ dump = bdevsw[major(dumpdev)].d_dump;
+ error = 0;
+
+ bytes = n = i = memseg = 0;
+ maddr = 0;
+ va = 0;
+#if 0
+ for (memseg = 0; memseg < mem_cluster_cnt; memseg++) {
+ maddr = mem_clusters[memseg].start;
+ bytes = mem_clusters[memseg].size;
+
+ for (i = 0; i < bytes; i += n, totalbytesleft -= n) {
+ /* Print out how many MBs we have left to go. */
+ if ((totalbytesleft % (1024*1024)) < BYTES_PER_DUMP)
+ printf("%ld ", totalbytesleft / (1024 * 1024));
+
+ /* Limit size for next transfer. */
+ n = bytes - i;
+ if (n > BYTES_PER_DUMP)
+ n = BYTES_PER_DUMP;
+ if (maddr > 0xffffffff) {
+ va = (void *)dumpmem_vaddr;
+ if (n > dumpmem_sz)
+ n = dumpmem_sz;
+ memcpy(va, (void *)PMAP_DIRECT_MAP(maddr), n);
+ } else {
+ va = (void *)PMAP_DIRECT_MAP(maddr);
+ }
+
+ error = (*dump)(dumpdev, blkno, va, n);
+ if (error)
+ goto err;
+ maddr += n;
+ blkno += btodb(n); /* XXX? */
+
+#if 0 /* XXX this doesn't work. grr. */
+ /* operator aborting dump? */
+ if (sget() != NULL) {
+ error = EINTR;
+ break;
+ }
+#endif
+ }
+ }
+#endif
+
+ err:
+ switch (error) {
+
+ case ENXIO:
+ printf("device bad\n");
+ break;
+
+ case EFAULT:
+ printf("device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("area improper\n");
+ break;
+
+ case EIO:
+ printf("i/o error\n");
+ break;
+
+ case EINTR:
+ printf("aborted from console\n");
+ break;
+
+ case 0:
+ printf("succeeded\n");
+ break;
+
+ default:
+ printf("error %d\n", error);
+ break;
+ }
+ printf("\n\n");
+ delay(5000000); /* 5 seconds */
+}
+
+
+/// XXX ?
+/*
+ * Size of memory segments, before any memory is stolen.
+ */
+phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
+int mem_cluster_cnt;
+/// XXX ?
+
+/*
+ * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers.
+ */
+int
+cpu_dumpsize(void)
+{
+ int size;
+
+ size = ALIGN(sizeof(kcore_seg_t)) +
+ ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t));
+ if (roundup(size, dbtob(1)) != dbtob(1))
+ return (-1);
+
+ return (1);
+}
+
+u_long
+cpu_dump_mempagecnt()
+{
+ return 0;
+}
+
+
+void
+install_coproc_handler()
+{
+}
+
+void collect_kernel_args(char *);
+void process_kernel_args(void);
+
+volatile int gdb_wc, gdb_w;
+
+void
+initarm(struct arm64_bootparams *abp)
+{
+ //struct efi_map_header *efihdr;
+ vaddr_t vstart, vend;
+ struct cpu_info *pcpup;
+ long kvo = abp->kern_delta;
+ //caddr_t kmdp;
+ paddr_t memstart;
+ psize_t memsize;
+ void *config = abp->arg2;
+ void *fdt;
+ int (*map_func_save)(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+
+#if 0
+ gdb_w = 1;
+ while(gdb_w)
+ ;
+#endif
+ // NOTE that 1GB of ram is mapped in by default in
+ // the bootstrap memory config, so nothing is necessary
+ // until pmap_bootstrap_finalize is called??
+ if (!fdt_init(config) || fdt_get_size(config) == 0)
+ panic("initarm: no FDT");
+
+ struct fdt_reg reg;
+ void *node;
+
+ node = fdt_find_node("/chosen");
+ if (node != NULL) {
+ char *args, *duid;
+ int len;
+
+ len = fdt_node_property(node, "bootargs", &args);
+ if (len > 0)
+ collect_kernel_args(args);
+
+ len = fdt_node_property(node, "openbsd,bootduid", &duid);
+ if (len == sizeof(bootduid))
+ memcpy(bootduid, duid, sizeof(bootduid));
+ }
+
+ node = fdt_find_node("/memory");
+ if (node == NULL || fdt_get_reg(node, 0, &reg))
+ panic("initarm: no memory specificed");
+
+ memstart = reg.addr;
+ memsize = reg.size;
+ if (reg.size > 0x80000000)
+ memsize = 0x80000000;
+
+#if 0
+ /* Load the physical memory ranges */
+ physmap_idx = 0;
+ efihdr = (struct efi_map_header *)preload_search_info(kmdp,
+ MODINFO_METADATA | MODINFOMD_EFI_MAP);
+ add_efi_map_entries(efihdr, physmap, &physmap_idx);
+#endif
+
+ /* Set the pcpu data, this is needed by pmap_bootstrap */
+ // smp
+ pcpup = &cpu_info_primary;
+ //pcpu_init(pcpup, 0, sizeof(struct pcpu));
+
+
+ /*
+ * Set the pcpu pointer with a backup in tpidr_el1 to be
+ * loaded when entering the kernel from userland.
+ */
+ __asm __volatile(
+ "mov x18, %0 \n"
+ "msr tpidr_el1, %0" :: "r"(pcpup));
+
+ {
+ extern char bootargs[MAX_BOOT_STRING];
+ printf("memsize %llx %llx bootargs [%s]\n", memstart, memsize, bootargs);
+ }
+ process_kernel_args();
+
+ if (gdb_wc >= 0) {
+ gdb_w = 1;
+ while(gdb_w)
+ ;
+ }
+
+ // PCPU_SET(curthread, &thread0);
+
+ /* Do basic tuning, hz etc */
+ // init_param1();
+
+ // cache_setup();
+
+ // XXX
+ paddr_t pmap_steal_avail(size_t size, int align, void **kva);
+
+ void _start(void);
+ long kernbase = (long)&_start & ~0x00fff;
+
+ /* Bootstrap enough of pmap to enter the kernel proper */
+ vstart = pmap_bootstrap(kvo, abp->kern_l1pt,
+ kernbase, esym,
+ memstart, memstart + memsize);
+
+ //arm_devmap_bootstrap(0, NULL);
+
+ //cninit();
+
+ // XX correctly sized?
+ proc0paddr = (struct user *)abp->kern_stack;
+ //msgbufinit(msgbufp, msgbufsize);
+ //mutex_init();
+ //init_param2(physmem);
+
+ //dbg_monitor_init();
+ //kdb_init();
+
+ msgbufaddr = (caddr_t)vstart;
+ msgbufphys = pmap_steal_avail(round_page(MSGBUFSIZE), PAGE_SIZE, NULL);
+ vstart += round_page(MSGBUFSIZE);
+
+ zero_page = vstart;
+ vstart += PAGE_SIZE;
+ copy_src_page = vstart;
+ vstart += PAGE_SIZE;
+ copy_dst_page = vstart;
+ vstart += PAGE_SIZE;
+
+ /*
+ * Allocate pages for an FDT copy.
+ */
+ if (fdt_get_size(config) != 0) {
+ uint32_t csize, size = round_page(fdt_get_size(config));
+ vaddr_t va;
+
+ paddr_t fpa = pmap_steal_avail(size, PAGE_SIZE, NULL);
+ memcpy((void*)fpa, config, size); // copy to physical address
+ for (va = (vaddr_t)vstart, csize = size;
+ csize > 0;
+ csize -= PAGE_SIZE, va += PAGE_SIZE, fpa += PAGE_SIZE)
+ {
+ pmap_kenter_cache(va, fpa, PROT_READ, PMAP_CACHE_WB);
+ }
+
+ fdt = (void *)vstart;
+ vstart += size;
+ }
+
+ /* XXX */
+#if 0
+ // XXX ?
+ vstart += reserve_dumppages( (caddr_t)(?address? + arm_kvm_stolen));
+#endif
+ /*
+ * Managed KVM space is what we have claimed up to end of
+ * mapped kernel buffers.
+ */
+ {
+ // export back to pmap
+ extern vaddr_t virtual_avail, virtual_end;
+ virtual_avail = vstart;
+ vend = VM_MAX_KERNEL_ADDRESS; // XXX
+ virtual_end = vend;
+ }
+
+ /* Now we can reinit the FDT, using the virtual address. */
+ if (fdt)
+ fdt_init(fdt);
+
+// XXX
+int pmap_bootstrap_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp);
+
+ map_func_save = arm64_bs_tag._space_map;
+ arm64_bs_tag._space_map = pmap_bootstrap_bs_map;
+
+ // cninit
+ consinit();
+
+ arm64_bs_tag._space_map = map_func_save;
+
+ /* XXX */
+ pmap_avail_fixup();
+
+ uvmexp.pagesize = PAGE_SIZE;
+ uvm_setpagesize();
+
+ pmap_physload_avail();
+
+ //early_boot = 0;
+
+ softintr_init();
+ splraise(IPL_IPI);
+}
+
+int comcnspeed = B115200;
+char bootargs[MAX_BOOT_STRING];
+
+void
+collect_kernel_args(char *args)
+{
+ /* Make a local copy of the bootargs */
+ strncpy(bootargs, args, MAX_BOOT_STRING - sizeof(int));
+}
+void
+process_kernel_args(void)
+{
+ char *cp = bootargs;
+
+ if (cp[0] == '\0') {
+ boothowto = RB_AUTOBOOT;
+ return;
+ }
+
+ boothowto = 0;
+
+ /* Make a local copy of the bootargs */
+ strncpy(bootargs, cp, MAX_BOOT_STRING - sizeof(int));
+
+ cp = bootargs;
+ boot_file = bootargs;
+
+ /* Skip the kernel image filename */
+ while (*cp != ' ' && *cp != 0)
+ ++cp;
+
+ if (*cp != 0)
+ *cp++ = 0;
+
+ while (*cp == ' ')
+ ++cp;
+
+ boot_args = cp;
+
+ printf("bootfile: %s\n", boot_file);
+ printf("bootargs: %s\n", boot_args);
+
+ /* Setup pointer to boot flags */
+ while (*cp != '-')
+ if (*cp++ == '\0')
+ return;
+
+ for (;*++cp;) {
+ int fl;
+
+ fl = 0;
+ switch(*cp) {
+ case 'a':
+ fl |= RB_ASKNAME;
+ break;
+ case 'c':
+ fl |= RB_CONFIG;
+ break;
+ case 'd':
+ fl |= RB_KDB;
+ break;
+ case 's':
+ fl |= RB_SINGLE;
+ break;
+// hack
+ case 'g':
+ gdb_wc = 0;
+ break;
+// hack
+ case '1':
+ comcnspeed = B115200;
+ break;
+ case '9':
+ comcnspeed = B9600;
+ break;
+ default:
+ printf("unknown option `%c'\n", *cp);
+ break;
+ }
+ boothowto |= fl;
+ }
+}
+volatile int gdb_wc=-1;
+int gdb_c=0;
+void dbg(int index, long arg0, long arg1)
+{
+ if (gdb_wc > 0) {
+ gdb_wc--;
+ }
+ if (gdb_wc==-1) {
+ gdb_c++;
+ }
+ if (gdb_wc == 0)
+ gdb_w = 1;
+ while(gdb_w)
+ ;
+}
+void prt(char *fmt, long arg0, long arg1, long arg2)
+{
+}
+
+
+/*
+ * allow bootstrap to steal KVA after machdep has given it back to pmap.
+ * XXX - need a mechanism to prevent this from being used too early or late.
+ */
+int
+pmap_bootstrap_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ u_long startpa, pa, endpa;
+ vaddr_t va;
+
+ extern vaddr_t virtual_avail, virtual_end;
+
+ va = virtual_avail; // steal memory from virtual avail.
+
+ if (va == 0)
+ panic("pmap_bootstrap_bs_map, no virtual avail");
+
+ startpa = trunc_page(bpa);
+ endpa = round_page((bpa + size));
+
+ *bshp = (bus_space_handle_t)(va + (bpa - startpa));
+
+ for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
+ pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE,
+ PMAP_CACHE_CI);
+
+ virtual_avail = va;
+
+ return 0;
+}
+
+// debug function, not certain where this should go
+
+void
+dumpregs(struct trapframe *frame)
+{
+ int i;
+ for (i = 0; i < 30; i+=2) {
+ printf("x%02d: 0x%016llx 0x%016llx\n",
+ i, frame->tf_x[i], frame->tf_x[i+1]);
+ }
+ printf("sp: 0x%016llx\n", frame->tf_sp);
+ printf("lr: 0x%016llx\n", frame->tf_lr);
+ printf("pc: 0x%016llx\n", frame->tf_elr);
+ printf("spsr: 0x%016llx\n", frame->tf_spsr);
+}
diff --git a/sys/arch/arm64/arm64/mem.c b/sys/arch/arm64/arm64/mem.c
new file mode 100644
index 00000000000..8125ae43728
--- /dev/null
+++ b/sys/arch/arm64/arm64/mem.c
@@ -0,0 +1,270 @@
+/* $OpenBSD: mem.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: mem.c,v 1.11 2003/10/16 12:02:58 jdolecek Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1988 University of Utah.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Memory special file
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+
+#include <machine/cpu.h>
+#include <arm64/conf.h>
+
+#include <uvm/uvm_extern.h>
+
+extern char *memhook; /* poor name! */
+caddr_t zeropage;
+int physlock;
+
+/* open counter for aperture */
+#ifdef APERTURE
+static int ap_open_count = 0;
+extern int allowaperture;
+#endif
+
+
+/*ARGSUSED*/
+int
+mmopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ switch (minor(dev)) {
+ case 0:
+ case 1:
+ case 2:
+ case 12:
+ break;
+#ifdef APERTURE
+ case 4:
+ if (suser(p, 0) != 0 || !allowaperture)
+ return (EPERM);
+
+ /* authorize only one simultaneous open() */
+ if (ap_open_count > 0)
+ return(EPERM);
+ ap_open_count++;
+ break;
+#endif
+ default:
+ return (ENXIO);
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+mmclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+#ifdef APERTURE
+ if (minor(dev) == 4)
+ ap_open_count = 0;
+#endif
+ return (0);
+}
+#define DEV_MEM 0
+#define DEV_KMEM 1
+#define DEV_NULL 2
+#define DEV_ZERO 12
+
+/*ARGSUSED*/
+int
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register vaddr_t o, v;
+ register int c;
+ register struct iovec *iov;
+ int error = 0;
+ vm_prot_t prot;
+
+ if (minor(dev) == DEV_MEM) {
+ /* lock against other uses of shared vmmap */
+ while (physlock > 0) {
+ physlock++;
+ error = tsleep((caddr_t)&physlock, PZERO | PCATCH,
+ "mmrw", 0);
+ if (error)
+ return (error);
+ }
+ physlock = 1;
+ }
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+ case DEV_MEM:
+ v = uio->uio_offset;
+ prot = uio->uio_rw == UIO_READ ? PROT_READ :
+ PROT_WRITE;
+ pmap_enter(pmap_kernel(), (vaddr_t)memhook,
+ trunc_page(v), prot, prot|PMAP_WIRED);
+ pmap_update(pmap_kernel());
+ o = uio->uio_offset & PGOFSET;
+ c = min(uio->uio_resid, (int)(PAGE_SIZE - o));
+ error = uiomove((caddr_t)memhook + o, c, uio);
+ pmap_remove(pmap_kernel(), (vaddr_t)memhook,
+ (vaddr_t)memhook + PAGE_SIZE);
+ pmap_update(pmap_kernel());
+ break;
+
+ case DEV_KMEM:
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (!uvm_kernacc((caddr_t)v, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return (EFAULT);
+ error = uiomove((caddr_t)v, c, uio);
+ break;
+
+ case DEV_NULL:
+ if (uio->uio_rw == UIO_WRITE)
+ uio->uio_resid = 0;
+ return (0);
+
+ case DEV_ZERO:
+ if (uio->uio_rw == UIO_WRITE) {
+ uio->uio_resid = 0;
+ return (0);
+ }
+ if (zeropage == NULL)
+ zeropage = malloc(PAGE_SIZE, M_TEMP,
+ M_WAITOK | M_ZERO);
+ c = min(iov->iov_len, PAGE_SIZE);
+ error = uiomove(zeropage, c, uio);
+ break;
+
+ default:
+ return (ENXIO);
+ }
+ }
+ if (minor(dev) == DEV_MEM) {
+/*unlock:*/
+ if (physlock > 1)
+ wakeup((caddr_t)&physlock);
+ physlock = 0;
+ }
+ return (error);
+}
+
+paddr_t
+mmmmap(dev, off, prot)
+ dev_t dev;
+ off_t off;
+ int prot;
+{
+ struct proc *p = curproc; /* XXX */
+
+ /*
+ * /dev/mem is the only one that makes sense through this
+ * interface. For /dev/kmem any physaddr we return here
+ * could be transient and hence incorrect or invalid at
+ * a later time. /dev/null just doesn't make any sense
+ * and /dev/zero is a hack that is handled via the default
+ * pager in mmap().
+ */
+ if (minor(dev) != DEV_MEM)
+ return (-1);
+
+ /* minor device 0 is physical memory */
+
+ if ((paddr_t)off >= ptoa((paddr_t)physmem) &&
+ suser(p, 0) != 0)
+ return -1;
+ return off;
+}
+/*ARGSUSED*/
+int
+mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ return (EOPNOTSUPP);
+}
+
diff --git a/sys/arch/arm64/arm64/pmap.c b/sys/arch/arm64/arm64/pmap.c
new file mode 100644
index 00000000000..89a5687e4f4
--- /dev/null
+++ b/sys/arch/arm64/arm64/pmap.c
@@ -0,0 +1,2397 @@
+/* $OpenBSD: pmap.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2008-2009,2014-2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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/malloc.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/systm.h>
+#include <sys/pool.h>
+#include <sys/atomic.h>
+
+#include <uvm/uvm.h>
+
+#include "arm64/vmparam.h"
+#include "arm64/pmap.h"
+#include "machine/pcb.h"
+
+#include <machine/db_machdep.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_output.h>
+
+#if 0
+#define STATIC /* static */
+#define __inline /* inline */
+#else
+#define STATIC static
+#define __inline inline
+
+#endif
+
+void pmap_setttb(struct proc *p, paddr_t pcb_pagedir, struct pcb *);
+void arm64_tlbi_asid(vaddr_t va, int asid);
+void pmap_free_asid(pmap_t pm);
+
+// using PHYS_TO_VM_PAGE does not do what is desired, so instead of
+// using that API, create our own which will store ranges of memory
+// and default to caching those pages when mapped
+
+struct {
+ uint64_t start;
+ uint64_t end;
+} pmap_memregions[8];
+
+int pmap_memcount = 0;
+
+int
+pmap_pa_is_mem(uint64_t pa)
+{
+ int i;
+ // NOTE THIS REQUIRES TABLE TO BE SORTED
+ for (i = 0; i < pmap_memcount; i++) {
+ if (pa < pmap_memregions[i].start)
+ return 0;
+ if (pa < pmap_memregions[i].end)
+ return 1;
+ }
+ return 0;
+}
+
+/* Write back D-cache to PoU */
+void
+dcache_wb_pou(vaddr_t va, vsize_t size)
+{
+ vsize_t off;
+ // XXX size.
+#define CACHE_LINE_SIZE 128
+
+ for (off = 0; off <size; off += CACHE_LINE_SIZE)
+ __asm __volatile("dc CVAU,%0"::"r"(va+off));
+}
+
+#if 0
+/* Write back and invalidate D-cache to PoC */
+STATIC __inline void
+dcache_wbinv_poc(vaddr_t sva, paddr_t pa, vsize_t size)
+{
+ // XXX needed?
+ for (off = 0; off <size; off += CACHE_LINE_SIZE)
+ __asm __volatile("dc CVAC,%0"::"r"(va+off));
+}
+#endif
+
+STATIC __inline void
+ttlb_flush(pmap_t pm, vaddr_t va)
+{
+ arm64_tlbi_asid(va, pm->pm_asid);
+}
+
+STATIC __inline void
+ttlb_flush_range(pmap_t pm, vaddr_t va, vsize_t size)
+{
+ vaddr_t eva = va + size;
+
+ __asm __volatile("dsb sy");
+ // if size is over 512 pages, just flush the entire cache !?!?!
+ if (size >= (512 * PAGE_SIZE)) {
+ __asm __volatile("tlbi vmalle1is");
+ return ;
+ }
+
+ for ( ; va < eva; va += PAGE_SIZE)
+ arm64_tlbi_asid(va, pm->pm_asid);
+ __asm __volatile("dsb sy");
+}
+
+void
+arm64_tlbi_asid(vaddr_t va, int asid)
+{
+ vaddr_t resva;
+ if (asid == -1) {
+ resva = ((va>>PAGE_SHIFT) & (1ULL << 44) -1) ;
+ __asm volatile ("TLBI VAALE1IS, %x0":: "r"(resva));
+ return;
+ }
+ resva = ((va >> PAGE_SHIFT) & (1ULL << 44) -1) |
+ ((unsigned long long)asid << 48);
+ __asm volatile ("TLBI VAE1IS, %x0" :: "r"(resva));
+}
+
+struct pmap kernel_pmap_;
+
+LIST_HEAD(pted_pv_head, pte_desc);
+
+struct pte_desc {
+ LIST_ENTRY(pte_desc) pted_pv_list;
+ uint64_t pted_pte;
+ pmap_t pted_pmap;
+ vaddr_t pted_va;
+};
+
+/* VP routines */
+int pmap_vp_enter(pmap_t pm, vaddr_t va, struct pte_desc *pted, int flags);
+struct pte_desc *pmap_vp_remove(pmap_t pm, vaddr_t va);
+void pmap_vp_destroy(pmap_t pm);
+struct pte_desc *pmap_vp_lookup(pmap_t pm, vaddr_t va, uint64_t **);
+
+/* PV routines */
+void pmap_enter_pv(struct pte_desc *pted, struct vm_page *);
+void pmap_remove_pv(struct pte_desc *pted);
+
+void _pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, int flags,
+ int cache);
+
+void pmap_allocate_asid(pmap_t);
+
+struct pmapvp0 {
+ uint64_t l0[VP_IDX0_CNT];
+ struct pmapvp1 *vp[VP_IDX0_CNT];
+};
+
+struct pmapvp1 {
+ uint64_t l1[VP_IDX1_CNT];
+ struct pmapvp2 *vp[VP_IDX1_CNT];
+};
+
+struct pmapvp2 {
+ uint64_t l2[VP_IDX2_CNT];
+ struct pmapvp3 *vp[VP_IDX2_CNT];
+};
+
+struct pmapvp3 {
+ uint64_t l3[VP_IDX3_CNT];
+ struct pte_desc *vp[VP_IDX3_CNT];
+};
+CTASSERT(sizeof(struct pmapvp0) == sizeof(struct pmapvp1));
+CTASSERT(sizeof(struct pmapvp0) == sizeof(struct pmapvp2));
+CTASSERT(sizeof(struct pmapvp0) == sizeof(struct pmapvp3));
+
+
+void pmap_remove_pted(pmap_t pm, struct pte_desc *pted);
+void pmap_kremove_pg(vaddr_t va);
+void pmap_set_l1(struct pmap *pm, uint64_t va, struct pmapvp1 *l1_va, paddr_t l1_pa);
+void pmap_set_l2(struct pmap *pm, uint64_t va, struct pmapvp2 *l2_va, paddr_t l2_pa);
+void pmap_set_l3(struct pmap *pm, uint64_t va, struct pmapvp3 *l3_va, paddr_t l3_pa);
+
+
+/* XXX */
+void
+pmap_fill_pte(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted,
+ vm_prot_t prot, int flags, int cache);
+void pte_insert(struct pte_desc *pted);
+void pte_remove(struct pte_desc *pted, int);
+void pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable);
+void pmap_pinit(pmap_t pm);
+void pmap_release(pmap_t pm);
+//vaddr_t pmap_steal_memory(vsize_t size, vaddr_t *start, vaddr_t *end);
+paddr_t arm_kvm_stolen;
+paddr_t pmap_steal_avail(size_t size, int align, void **kva);
+void pmap_remove_avail(paddr_t base, paddr_t end);
+void pmap_avail_fixup(void);
+vaddr_t pmap_map_stolen(vaddr_t);
+void pmap_physload_avail(void);
+extern caddr_t msgbufaddr;
+
+
+/* XXX - panic on pool get failures? */
+struct pool pmap_pmap_pool;
+struct pool pmap_pted_pool;
+struct pool pmap_vp_pool;
+
+/* list of L1 tables */
+
+int pmap_initialized = 0;
+
+struct mem_region {
+ vaddr_t start;
+ vsize_t size;
+};
+
+struct mem_region pmap_avail_regions[10];
+struct mem_region pmap_allocated_regions[10];
+struct mem_region *pmap_avail = &pmap_avail_regions[0];
+struct mem_region *pmap_allocated = &pmap_allocated_regions[0];
+int pmap_cnt_avail, pmap_cnt_allocated;
+uint64_t pmap_avail_kvo;
+
+
+/* virtual to physical helpers */
+STATIC __inline int
+VP_IDX0(vaddr_t va)
+{
+ return (va >> VP_IDX0_POS) & VP_IDX0_MASK;
+}
+
+STATIC __inline int
+VP_IDX1(vaddr_t va)
+{
+ return (va >> VP_IDX1_POS) & VP_IDX1_MASK;
+ return 0;
+}
+
+STATIC __inline int
+VP_IDX2(vaddr_t va)
+{
+ return (va >> VP_IDX2_POS) & VP_IDX2_MASK;
+ return 0;
+}
+
+STATIC __inline int
+VP_IDX3(vaddr_t va)
+{
+ return (va >> VP_IDX3_POS) & VP_IDX3_MASK;
+ return 0;
+}
+
+#if 0
+STATIC __inline vaddr_t
+VP_IDXTOVA(int kern, int idx0, int idx1, int idx2, int idx3,
+ int mask)
+{
+ vaddr_t va = 0;
+ if (kern)
+ va |= 0xffffff8000000000ULL;
+ va |= (long)(idx0 & VP_IDX0_MASK) << VP_IDX0_POS;
+ va |= (long)(idx1 & VP_IDX1_MASK) << VP_IDX1_POS;
+ va |= (long)(idx2 & VP_IDX2_MASK) << VP_IDX2_POS;
+ va |= (long)(idx3 & VP_IDX3_MASK) << VP_IDX3_POS;
+ va |= mask & 0xfff; // page offset;
+
+ return va;
+}
+#endif
+
+const struct kmem_pa_mode kp_lN = {
+ .kp_constraint = &no_constraint,
+ .kp_maxseg = 1,
+ .kp_align = 4096,
+ .kp_zero = 1,
+};
+
+
+/*
+ * This is used for pmap_kernel() mappings, they are not to be removed
+ * from the vp table because they were statically initialized at the
+ * initial pmap initialization. This is so that memory allocation
+ * is not necessary in the pmap_kernel() mappings.
+ * Otherwise bad race conditions can appear.
+ */
+struct pte_desc *
+pmap_vp_lookup(pmap_t pm, vaddr_t va, uint64_t **pl3entry)
+{
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ struct pte_desc *pted;
+
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[VP_IDX0(va)];
+ if (vp1 == NULL) {
+ return NULL;
+ }
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+
+ vp2 = vp1->vp[VP_IDX1(va)];
+ if (vp2 == NULL) {
+ return NULL;
+ }
+
+ vp3 = vp2->vp[VP_IDX2(va)];
+ if (vp3 == NULL) {
+ return NULL;
+ }
+
+ pted = vp3->vp[VP_IDX3(va)];
+ if (pl3entry != NULL)
+ *pl3entry = &(vp3->l3[VP_IDX3(va)]);
+
+ return pted;
+}
+
+/*
+ * Remove, and return, pted at specified address, NULL if not present
+ */
+struct pte_desc *
+pmap_vp_remove(pmap_t pm, vaddr_t va)
+{
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ struct pte_desc *pted;
+
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[VP_IDX0(va)];
+ if (vp1 == NULL) {
+ return NULL;
+ }
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+
+ vp2 = vp1->vp[VP_IDX1(va)];
+ if (vp2 == NULL) {
+ return NULL;
+ }
+
+ vp3 = vp2->vp[VP_IDX2(va)];
+ if (vp3 == NULL) {
+ return NULL;
+ }
+
+ pted = vp3->vp[VP_IDX3(va)];
+ vp3->vp[VP_IDX3(va)] = NULL;
+
+ return pted;
+}
+
+
+/*
+ * Create a V -> P mapping for the given pmap and virtual address
+ * with reference to the pte descriptor that is used to map the page.
+ * This code should track allocations of vp table allocations
+ * so they can be freed efficiently.
+ *
+ * XXX it may be possible to save some bits of count in the
+ * upper address bits of the pa or the pte entry.
+ * However that does make populating the other bits more tricky.
+ * each level has 512 entries, so that mean 9 bits to store
+ * stash 3 bits each in the first 3 entries?
+ */
+int
+pmap_vp_enter(pmap_t pm, vaddr_t va, struct pte_desc *pted, int flags)
+{
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+
+ int vp_pool_flags;
+ if (pm == pmap_kernel()) {
+ vp_pool_flags = PR_NOWAIT;
+ } else {
+ vp_pool_flags = PR_WAITOK |PR_ZERO;
+ }
+
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[VP_IDX0(va)];
+ if (vp1 == NULL) {
+ vp1 = pool_get(&pmap_vp_pool, vp_pool_flags);
+ if (vp1 == NULL) {
+ if ((flags & PMAP_CANFAIL) == 0)
+ return ENOMEM;
+ panic("unable to allocate L1");
+ }
+ pmap_set_l1(pm, va, vp1, 0);
+ }
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+
+ vp2 = vp1->vp[VP_IDX1(va)];
+ if (vp2 == NULL) {
+ vp2 = pool_get(&pmap_vp_pool, vp_pool_flags);
+ if (vp2 == NULL) {
+ if ((flags & PMAP_CANFAIL) == 0)
+ return ENOMEM;
+ panic("unable to allocate L2");
+ }
+ pmap_set_l2(pm, va, vp2, 0);
+ }
+
+ vp3 = vp2->vp[VP_IDX2(va)];
+ if (vp3 == NULL) {
+ vp3 = pool_get(&pmap_vp_pool, vp_pool_flags);
+ if (vp3 == NULL) {
+ if ((flags & PMAP_CANFAIL) == 0)
+ return ENOMEM;
+ panic("unable to allocate L3");
+ }
+ pmap_set_l3(pm, va, vp3, 0);
+ }
+
+ vp3->vp[VP_IDX3(va)] = pted;
+ return 0;
+}
+
+u_int32_t PTED_MANAGED(struct pte_desc *pted);
+u_int32_t PTED_WIRED(struct pte_desc *pted);
+u_int32_t PTED_VALID(struct pte_desc *pted);
+
+u_int32_t
+PTED_MANAGED(struct pte_desc *pted)
+{
+ return (pted->pted_va & PTED_VA_MANAGED_M);
+}
+
+u_int32_t
+PTED_WIRED(struct pte_desc *pted)
+{
+ return (pted->pted_va & PTED_VA_WIRED_M);
+}
+
+u_int32_t
+PTED_VALID(struct pte_desc *pted)
+{
+ return (pted->pted_pte != 0);
+}
+
+/*
+ * PV entries -
+ * manipulate the physical to virtual translations for the entire system.
+ *
+ * QUESTION: should all mapped memory be stored in PV tables? Or
+ * is it alright to only store "ram" memory. Currently device mappings
+ * are not stored.
+ * It makes sense to pre-allocate mappings for all of "ram" memory, since
+ * it is likely that it will be mapped at some point, but would it also
+ * make sense to use a tree/table like is use for pmap to store device
+ * mappings?
+ * Further notes: It seems that the PV table is only used for pmap_protect
+ * and other paging related operations. Given this, it is not necessary
+ * to store any pmap_kernel() entries in PV tables and does not make
+ * sense to store device mappings in PV either.
+ *
+ * Note: unlike other powerpc pmap designs, the array is only an array
+ * of pointers. Since the same structure is used for holding information
+ * in the VP table, the PV table, and for kernel mappings, the wired entries.
+ * Allocate one data structure to hold all of the info, instead of replicating
+ * it multiple times.
+ *
+ * One issue of making this a single data structure is that two pointers are
+ * wasted for every page which does not map ram (device mappings), this
+ * should be a low percentage of mapped pages in the system, so should not
+ * have too noticable unnecessary ram consumption.
+ */
+
+void
+pmap_enter_pv(struct pte_desc *pted, struct vm_page *pg)
+{
+ // XXX does this test mean that some pages try to be managed,
+ // but this is called too soon?
+ if (__predict_false(!pmap_initialized)) {
+ return;
+ }
+
+ LIST_INSERT_HEAD(&(pg->mdpage.pv_list), pted, pted_pv_list);
+ pted->pted_va |= PTED_VA_MANAGED_M;
+}
+
+void
+pmap_remove_pv(struct pte_desc *pted)
+{
+ LIST_REMOVE(pted, pted_pv_list);
+}
+
+volatile int supportuserland;
+
+int
+pmap_enter(pmap_t pm, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
+{
+ struct pte_desc *pted;
+ struct vm_page *pg;
+ int s;
+ int need_sync = 0;
+ int cache;
+ int error;
+
+ //if (!cold) printf("%s: %x %x %x %x %x %x\n", __func__, va, pa, prot, flags, pm, pmap_kernel());
+
+ /* MP - Acquire lock for this pmap */
+
+ s = splvm();
+ pted = pmap_vp_lookup(pm, va, NULL);
+ if (pted && PTED_VALID(pted)) {
+ pmap_remove_pted(pm, pted);
+ /* we lost our pted if it was user */
+ if (pm != pmap_kernel())
+ pted = pmap_vp_lookup(pm, va, NULL);
+ }
+
+ pm->pm_stats.resident_count++;
+
+ /* Do not have pted for this, get one and put it in VP */
+ if (pted == NULL) {
+ pted = pool_get(&pmap_pted_pool, PR_NOWAIT | PR_ZERO);
+ if (pted == NULL) {
+ if ((flags & PMAP_CANFAIL) == 0) {
+ error = ENOMEM;
+ goto out;
+ }
+ panic("pmap_enter: failed to allocate pted");
+ }
+ if (pmap_vp_enter(pm, va, pted, flags)) {
+ if ((flags & PMAP_CANFAIL) == 0) {
+ error = ENOMEM;
+ pool_put(&pmap_pted_pool, pted);
+ goto out;
+ }
+ panic("pmap_enter: failed to allocate L2/L3");
+ }
+ }
+
+ /* Calculate PTE */
+ if (pmap_pa_is_mem(pa)) {
+ pg = PHYS_TO_VM_PAGE(pa);
+ /* max cacheable */
+ cache = PMAP_CACHE_WB; /* managed memory is cacheable */
+ } else {
+ pg = NULL;
+ cache = PMAP_CACHE_CI;
+ }
+
+ /*
+ * If it should be enabled _right now_, we can skip doing ref/mod
+ * emulation. Any access includes reference, modified only by write.
+ */
+ if (pg != NULL &&
+ ((flags & PROT_MASK) || (pg->pg_flags & PG_PMAP_REF))) {
+ pg->pg_flags |= PG_PMAP_REF;
+ if ((prot & PROT_WRITE) && (flags & PROT_WRITE)) {
+ pg->pg_flags |= PG_PMAP_MOD;
+ }
+ }
+
+ pmap_fill_pte(pm, va, pa, pted, prot, flags, cache);
+
+ if (pg != NULL) {
+ pmap_enter_pv(pted, pg); /* only managed mem */
+ }
+
+ /*
+ * Insert into table, if this mapping said it needed to be mapped
+ * now.
+ */
+ if (flags & (PROT_READ|PROT_WRITE|PMAP_WIRED)) {
+ pte_insert(pted);
+ }
+
+// cpu_dcache_inv_range(va & PAGE_MASK, PAGE_SIZE);
+// cpu_sdcache_inv_range(va & PAGE_MASK, pa & PAGE_MASK, PAGE_SIZE);
+// cpu_drain_writebuf();
+ ttlb_flush(pm, va & PTE_RPGN);
+
+ if (prot & PROT_EXEC) {
+ if (pg != NULL) {
+ need_sync = ((pg->pg_flags & PG_PMAP_EXE) == 0);
+ atomic_setbits_int(&pg->pg_flags, PG_PMAP_EXE);
+ } else
+ need_sync = 1;
+ } else {
+ /*
+ * Should we be paranoid about writeable non-exec
+ * mappings ? if so, clear the exec tag
+ */
+ if ((prot & PROT_WRITE) && (pg != NULL))
+ atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE);
+ }
+
+ splx(s);
+
+#if 0
+ /* only instruction sync executable pages */
+ if (need_sync)
+ pmap_syncicache_user_virt(pm, va);
+#endif
+
+ error = 0;
+out:
+ /* MP - free pmap lock */
+ return error;
+}
+
+
+/*
+ * Remove the given range of mapping entries.
+ */
+void
+pmap_remove(pmap_t pm, vaddr_t sva, vaddr_t eva)
+{
+ struct pte_desc *pted;
+ vaddr_t va;
+
+ for (va = sva; va < eva; va += PAGE_SIZE) {
+ pted = pmap_vp_lookup(pm, va, NULL);
+
+ if (pted == NULL)
+ continue;
+
+ if (pted->pted_va & PTED_VA_WIRED_M) {
+ pm->pm_stats.wired_count--;
+ pted->pted_va &= ~PTED_VA_WIRED_M;
+ }
+
+ if (PTED_VALID(pted))
+ pmap_remove_pted(pm, pted);
+ }
+}
+
+/*
+ * remove a single mapping, notice that this code is O(1)
+ */
+void
+pmap_remove_pted(pmap_t pm, struct pte_desc *pted)
+{
+ int s;
+
+ s = splvm();
+ pm->pm_stats.resident_count--;
+
+ if (pted->pted_va & PTED_VA_WIRED_M) {
+ pm->pm_stats.wired_count--;
+ pted->pted_va &= ~PTED_VA_WIRED_M;
+ }
+
+ __asm __volatile("dsb sy");
+ //dcache_wbinv_poc(va & PTE_RPGN, pted->pted_pte & PTE_RPGN, PAGE_SIZE);
+
+ pte_remove(pted, pm != pmap_kernel());
+
+ ttlb_flush(pm, pted->pted_va & PTE_RPGN);
+
+ if (pted->pted_va & PTED_VA_EXEC_M) {
+ pted->pted_va &= ~PTED_VA_EXEC_M;
+ }
+
+ pted->pted_pte = 0;
+
+ if (PTED_MANAGED(pted))
+ pmap_remove_pv(pted);
+
+ if (pm != pmap_kernel())
+ pool_put(&pmap_pted_pool, pted);
+ splx(s);
+}
+
+
+/*
+ * Enter a kernel mapping for the given page.
+ * kernel mappings have a larger set of prerequisites than normal mappings.
+ *
+ * 1. no memory should be allocated to create a kernel mapping.
+ * 2. a vp mapping should already exist, even if invalid. (see 1)
+ * 3. all vp tree mappings should already exist (see 1)
+ *
+ */
+void
+_pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, int flags, int cache)
+{
+ struct pte_desc *pted;
+ int s;
+ pmap_t pm;
+
+ //if (!cold) printf("%s: %x %x %x %x %x\n", __func__, va, pa, prot, flags, cache);
+
+ pm = pmap_kernel();
+
+ /* MP - lock pmap. */
+ s = splvm();
+
+ pted = pmap_vp_lookup(pm, va, NULL);
+
+ /* Do not have pted for this, get one and put it in VP */
+ if (pted == NULL) {
+ panic("pted not preallocated in pmap_kernel() va %lx pa %lx\n",
+ va, pa);
+ }
+
+ if (pted && PTED_VALID(pted))
+ pmap_kremove_pg(va); /* pted is reused */
+
+ pm->pm_stats.resident_count++;
+
+ if (cache == PMAP_CACHE_DEFAULT) {
+ if (pmap_pa_is_mem(pa)) {
+ /* MAXIMUM cacheability */
+ cache = PMAP_CACHE_WB; /* managed memory is cacheable */
+ } else {
+ printf("entering page unmapped %llx %llx\n", va, pa);
+ cache = PMAP_CACHE_CI;
+ }
+ }
+
+ flags |= PMAP_WIRED; /* kernel mappings are always wired. */
+ /* Calculate PTE */
+ pmap_fill_pte(pm, va, pa, pted, prot, flags, cache);
+
+ /*
+ * Insert into table
+ * We were told to map the page, probably called from vm_fault,
+ * so map the page!
+ */
+ pte_insert(pted);
+
+ ttlb_flush(pm, va & PTE_RPGN);
+
+ splx(s);
+}
+
+void
+pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
+{
+ _pmap_kenter_pa(va, pa, prot, prot, PMAP_CACHE_DEFAULT);
+}
+
+void
+pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable)
+{
+ _pmap_kenter_pa(va, pa, prot, prot, cacheable);
+}
+
+/*
+ * remove kernel (pmap_kernel()) mapping, one page
+ */
+void
+pmap_kremove_pg(vaddr_t va)
+{
+ struct pte_desc *pted;
+ pmap_t pm;
+ int s;
+
+ //if (!cold) printf("%s: %x\n", __func__, va);
+
+ pm = pmap_kernel();
+ pted = pmap_vp_lookup(pm, va, NULL);
+ if (pted == NULL)
+ return;
+
+ if (!PTED_VALID(pted))
+ return; /* not mapped */
+
+ s = splvm();
+
+ pm->pm_stats.resident_count--;
+
+ /*
+ * Table needs to be locked here as well as pmap, and pv list.
+ * so that we know the mapping information is either valid,
+ * or that the mapping is not present in the hash table.
+ */
+ pte_remove(pted, 0);
+
+ ttlb_flush(pm, pted->pted_va & PTE_RPGN);
+
+ if (pted->pted_va & PTED_VA_EXEC_M)
+ pted->pted_va &= ~PTED_VA_EXEC_M;
+
+ if (PTED_MANAGED(pted))
+ pmap_remove_pv(pted);
+
+ if (pted->pted_va & PTED_VA_WIRED_M)
+ pm->pm_stats.wired_count--;
+
+ /* invalidate pted; */
+ pted->pted_pte = 0;
+ pted->pted_va = 0;
+
+ splx(s);
+}
+
+/*
+ * remove kernel (pmap_kernel()) mappings
+ */
+void
+pmap_kremove(vaddr_t va, vsize_t len)
+{
+ //if (!cold) printf("%s: %x %x\n", __func__, va, len);
+ for (len >>= PAGE_SHIFT; len >0; len--, va += PAGE_SIZE)
+ pmap_kremove_pg(va);
+}
+
+
+void
+pmap_fill_pte(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted,
+ vm_prot_t prot, int flags, int cache)
+{
+ pted->pted_va = va;
+ pted->pted_pmap = pm;
+
+ switch (cache) {
+ case PMAP_CACHE_WB:
+ break;
+ case PMAP_CACHE_WT:
+ break;
+ case PMAP_CACHE_CI:
+ break;
+ case PMAP_CACHE_PTE:
+ break;
+ case PMAP_CACHE_DEV:
+ break;
+ default:
+ panic("pmap_fill_pte:invalid cache mode");
+ }
+ pted->pted_va |= cache;
+
+ pted->pted_va |= prot & (PROT_READ|PROT_WRITE|PROT_EXEC);
+
+ if (flags & PMAP_WIRED) {
+ pted->pted_va |= PTED_VA_WIRED_M;
+ pm->pm_stats.wired_count++;
+ }
+
+ pted->pted_pte = pa & PTE_RPGN;
+ pted->pted_pte |= (flags & (PROT_READ|PROT_WRITE)) | (prot & PROT_EXEC);
+}
+
+
+/*
+ * Garbage collects the physical map system for pages which are
+ * no longer used. Success need not be guaranteed -- that is, there
+ * may well be pages which are not referenced, but others may be collected
+ * Called by the pageout daemon when pages are scarce.
+ */
+void
+pmap_collect(pmap_t pm)
+{
+ /* This could return unused v->p table layers which
+ * are empty.
+ * could malicious programs allocate memory and eat
+ * these wired pages? These are allocated via pool.
+ * Are there pool functions which could be called
+ * to lower the pool usage here?
+ */
+}
+
+/*
+ * Fill the given physical page with zeros.
+ * SMP: need multiple zero pages, one for each cpu.
+ * XXX
+ */
+void
+pmap_zero_page(struct vm_page *pg)
+{
+ //printf("%s\n", __func__);
+ paddr_t pa = VM_PAGE_TO_PHYS(pg);
+
+ /* simple_lock(&pmap_zero_page_lock); */
+ pmap_kenter_pa(zero_page, pa, PROT_READ|PROT_WRITE);
+
+ // XXX use better zero operation?
+ bzero((void *)zero_page, PAGE_SIZE);
+
+ // XXX better way to unmap this?
+ pmap_kremove_pg(zero_page);
+}
+
+/*
+ * copy the given physical page with zeros.
+ * SMP: need multiple copy va, one set for each cpu.
+ */
+void
+pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
+{
+ //printf("%s\n", __func__);
+ paddr_t srcpa = VM_PAGE_TO_PHYS(srcpg);
+ paddr_t dstpa = VM_PAGE_TO_PHYS(dstpg);
+ /* simple_lock(&pmap_copy_page_lock); */
+
+ pmap_kenter_pa(copy_src_page, srcpa, PROT_READ);
+ pmap_kenter_pa(copy_dst_page, dstpa, PROT_READ|PROT_WRITE);
+
+ bcopy((void *)copy_src_page, (void *)copy_dst_page, PAGE_SIZE);
+
+ pmap_kremove_pg(copy_src_page);
+ pmap_kremove_pg(copy_dst_page);
+ /* simple_unlock(&pmap_copy_page_lock); */
+}
+
+void
+pmap_pinit(pmap_t pm)
+{
+ // Build time asserts on some data structs. (vp3 is not same size)
+
+ bzero(pm, sizeof (struct pmap));
+ vaddr_t l0va;
+
+ /* Allocate a full L0/L1 table. */
+ if (pm->have_4_level_pt) {
+ while (pm->pm_vp.l0 == NULL) {
+ pm->pm_vp.l0 = pool_get(&pmap_vp_pool,
+ PR_WAITOK | PR_ZERO);
+ }
+ l0va = (vaddr_t) pm->pm_vp.l0->l0; // top level is l0
+ } else {
+ while (pm->pm_vp.l1 == NULL) {
+
+ pm->pm_vp.l1 = pool_get(&pmap_vp_pool,
+ PR_WAITOK | PR_ZERO);
+ }
+ l0va = (vaddr_t) pm->pm_vp.l1->l1; // top level is l1
+
+ }
+
+ //pmap_allocate_asid(pm); // by default global (allocate asid later!?!)
+ pm->pm_asid = -1;
+
+ pmap_extract(pmap_kernel(), l0va, (paddr_t *)&pm->pm_pt0pa);
+
+ pmap_reference(pm);
+}
+
+int pmap_vp_poolcache = 0; // force vp poolcache to allocate late.
+/*
+ * Create and return a physical map.
+ */
+pmap_t
+pmap_create()
+{
+ pmap_t pmap;
+ int s;
+
+ s = splvm();
+ pmap = pool_get(&pmap_pmap_pool, PR_WAITOK);
+ splx(s);
+ pmap_pinit(pmap);
+ if (pmap_vp_poolcache == 0) {
+ pool_setlowat(&pmap_vp_pool, 20);
+ pmap_vp_poolcache = 20;
+ }
+ return (pmap);
+}
+
+/*
+ * Add a reference to a given pmap.
+ */
+void
+pmap_reference(pmap_t pm)
+{
+ /* simple_lock(&pmap->pm_obj.vmobjlock); */
+ pm->pm_refs++;
+ /* simple_unlock(&pmap->pm_obj.vmobjlock); */
+}
+
+/*
+ * Retire the given pmap from service.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_destroy(pmap_t pm)
+{
+ int refs;
+ int s;
+
+ /* simple_lock(&pmap->pm_obj.vmobjlock); */
+ refs = --pm->pm_refs;
+ /* simple_unlock(&pmap->pm_obj.vmobjlock); */
+ if (refs > 0)
+ return;
+
+ if (pm->pm_asid != -1) {
+ pmap_free_asid(pm);
+ }
+ /*
+ * reference count is zero, free pmap resources and free pmap.
+ */
+ pmap_release(pm);
+ s = splvm();
+ pool_put(&pmap_pmap_pool, pm);
+ splx(s);
+}
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ */
+void
+pmap_release(pmap_t pm)
+{
+ pmap_vp_destroy(pm);
+}
+
+void pmap_vp_destroy_l2_l3(pmap_t pm, struct pmapvp1 *vp1);
+void
+pmap_vp_destroy_l2_l3(pmap_t pm, struct pmapvp1 *vp1)
+{
+ int j, k, l, s;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ struct pte_desc *pted;
+
+ for (j = 0; j < VP_IDX1_CNT; j++) {
+ vp2 = vp1->vp[j];
+ if (vp2 == NULL)
+ continue;
+ vp1->vp[j] = NULL;
+ for (k = 0; k < VP_IDX2_CNT; k++) {
+ vp3 = vp2->vp[k];
+ if (vp3 == NULL)
+ continue;
+ vp2->vp[k] = NULL;
+ for (l = 0; l < VP_IDX3_CNT; l++) {
+ pted = vp3->vp[l];
+ if (pted == NULL)
+ continue;
+ vp3->vp[l] = NULL;
+
+ s = splvm();
+ pool_put(&pmap_pted_pool, pted);
+ splx(s);
+ }
+ pool_put(&pmap_vp_pool, vp3);
+ }
+ pool_put(&pmap_vp_pool, vp2);
+ }
+}
+
+void
+pmap_vp_destroy(pmap_t pm)
+{
+ int i;
+ struct pmapvp0 *vp0;
+ struct pmapvp1 *vp1;
+
+ // Is there a better way to share this code between 3 and 4 level tables
+ // split the lower levels into a different function?
+ if (!pm->have_4_level_pt) {
+ pmap_vp_destroy_l2_l3(pm, pm->pm_vp.l1);
+ pool_put(&pmap_vp_pool, pm->pm_vp.l1);
+ pm->pm_vp.l1 = NULL;
+ return;
+ }
+
+ vp0 = pm->pm_vp.l0;
+ for (i = 0; i < VP_IDX0_CNT; i++) {
+ vp1 = vp0->vp[i];
+ if (vp1 == NULL)
+ continue;
+
+ pmap_vp_destroy_l2_l3(pm, vp1);
+
+ vp0->vp[i] = NULL;
+ pool_put(&pmap_vp_pool, vp1);
+ }
+ pm->pm_vp.l0 = NULL;
+ pool_put(&pmap_vp_pool, vp0);
+}
+
+/*
+ * Similar to pmap_steal_avail, but operating on vm_physmem since
+ * uvm_page_physload() has been called.
+ */
+vaddr_t
+pmap_steal_memory(vsize_t size, vaddr_t *start, vaddr_t *end)
+{
+ int segno;
+ u_int npg;
+ vaddr_t va;
+ paddr_t pa;
+ struct vm_physseg *seg;
+
+ size = round_page(size);
+ npg = atop(size);
+
+ for (segno = 0, seg = vm_physmem; segno < vm_nphysseg; segno++, seg++) {
+ if (seg->avail_end - seg->avail_start < npg)
+ continue;
+ /*
+ * We can only steal at an ``unused'' segment boundary,
+ * i.e. either at the start or at the end.
+ */
+ if (seg->avail_start == seg->start ||
+ seg->avail_end == seg->end)
+ break;
+ }
+ if (segno == vm_nphysseg)
+ va = 0;
+ else {
+ if (seg->avail_start == seg->start) {
+ pa = ptoa(seg->avail_start);
+ seg->avail_start += npg;
+ seg->start += npg;
+ } else {
+ pa = ptoa(seg->avail_end) - size;
+ seg->avail_end -= npg;
+ seg->end -= npg;
+ }
+ /*
+ * If all the segment has been consumed now, remove it.
+ * Note that the crash dump code still knows about it
+ * and will dump it correctly.
+ */
+ if (seg->start == seg->end) {
+ if (vm_nphysseg-- == 1)
+ panic("pmap_steal_memory: out of memory");
+ while (segno < vm_nphysseg) {
+ seg[0] = seg[1]; /* struct copy */
+ seg++;
+ segno++;
+ }
+ }
+
+ va = (vaddr_t)pa; /* 1:1 mapping */
+ bzero((void *)va, size);
+ }
+
+ if (start != NULL)
+ *start = VM_MIN_KERNEL_ADDRESS;
+ if (end != NULL)
+ *end = VM_MAX_KERNEL_ADDRESS;
+
+ return (va);
+}
+
+vaddr_t virtual_avail, virtual_end;
+
+STATIC __inline uint64_t
+VP_Lx(paddr_t pa)
+{
+ // This function takes the pa address given and manipulates it
+ // into the form that should be inserted into the VM table;
+ return pa | Lx_TYPE_PT;
+}
+
+void pmap_setup_avail( uint64_t ram_start, uint64_t ram_end, uint64_t kvo);
+/*
+ * Initialize pmap setup.
+ * ALL of the code which deals with avail needs rewritten as an actual
+ * memory allocation.
+ */
+CTASSERT(sizeof(struct pmapvp0) == 8192);
+
+int mappings_allocated = 0;
+int pted_allocated = 0;
+void prt(char *fmt, ...);
+
+vaddr_t
+pmap_bootstrap(long kvo, paddr_t lpt1, long kernelstart, long kernelend,
+ long ram_start, long ram_end)
+{
+ void *va;
+ paddr_t pa;
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ struct pte_desc *pted;
+ vaddr_t vstart;
+ int i, j, k;
+ int lb_idx2, ub_idx2;
+
+ prt("format string");
+ prt("does this %d work", 0);
+ prt("does this %d %d work", 5, 2);
+
+ pmap_setup_avail(ram_start, ram_end, kvo);
+
+ /* in theory we could start with just the memory in the kernel,
+ * however this could 'allocate' the bootloader and bootstrap
+ * vm table, which we may need to preserve until later.
+ * pmap_remove_avail(kernelstart-kvo, kernelend-kvo);
+ */
+ printf("removing %llx-%llx\n", ram_start, kernelstart+kvo); // preserve bootloader?
+ pmap_remove_avail(ram_start, kernelstart+kvo); // preserve bootloader?
+ printf("removing %llx-%llx\n", kernelstart+kvo, kernelend+kvo);
+ pmap_remove_avail(kernelstart+kvo, kernelend+kvo);
+
+
+ // KERNEL IS ASSUMED TO BE 39 bits (or less), start from L1, not L0
+ // ALSO kernel mappings may not cover enough ram to bootstrap
+ // so all accesses initializing tables must be done via physical
+ // pointers
+
+ pa = pmap_steal_avail(sizeof (struct pmapvp1), Lx_TABLE_ALIGN,
+ &va);
+ vp1 = (struct pmapvp1 *)pa;
+ pmap_kernel()->pm_vp.l1 = (struct pmapvp1 *)va;
+ pmap_kernel()->pm_pt0pa = pa;
+ pmap_kernel()->pm_asid = -1;
+
+ // allocate Lx entries
+ for (i = VP_IDX1(VM_MIN_KERNEL_ADDRESS);
+ i <= VP_IDX1(VM_MAX_KERNEL_ADDRESS);
+ i++) {
+ mappings_allocated++;
+ pa = pmap_steal_avail(sizeof (struct pmapvp2), Lx_TABLE_ALIGN,
+ &va);
+ vp2 = (struct pmapvp2 *)pa; // indexed physically
+ vp1->vp[i] = va;
+ vp1->l1[i] = VP_Lx(pa);
+
+ if (i == VP_IDX1(VM_MIN_KERNEL_ADDRESS)) {
+ lb_idx2 = VP_IDX2(VM_MIN_KERNEL_ADDRESS);
+ } else {
+ lb_idx2 = 0;
+ }
+ if (i == VP_IDX1(VM_MAX_KERNEL_ADDRESS)) {
+ ub_idx2 = VP_IDX2(VM_MAX_KERNEL_ADDRESS);
+ } else {
+ ub_idx2 = VP_IDX2_CNT-1;
+ }
+ for (j = lb_idx2; j <= ub_idx2; j++) {
+ mappings_allocated++;
+ pa = pmap_steal_avail(sizeof (struct pmapvp3),
+ Lx_TABLE_ALIGN, &va);
+ vp3 = (struct pmapvp3 *)pa; // indexed physically
+ vp2->vp[j] = va;
+ vp2->l2[j] = VP_Lx(pa);
+
+ }
+ }
+ // allocate Lx entries
+ for (i = VP_IDX1(VM_MIN_KERNEL_ADDRESS);
+ i <= VP_IDX1(VM_MAX_KERNEL_ADDRESS);
+ i++) {
+ // access must be performed physical
+ vp2 = (void *)((long)vp1->vp[i] + kvo);
+
+ if (i == VP_IDX1(VM_MIN_KERNEL_ADDRESS)) {
+ lb_idx2 = VP_IDX2(VM_MIN_KERNEL_ADDRESS);
+ } else {
+ lb_idx2 = 0;
+ }
+ if (i == VP_IDX1(VM_MAX_KERNEL_ADDRESS)) {
+ ub_idx2 = VP_IDX2(VM_MAX_KERNEL_ADDRESS);
+ } else {
+ ub_idx2 = VP_IDX2_CNT-1;
+ }
+ for (j = lb_idx2; j <= ub_idx2; j++) {
+ // access must be performed physical
+ vp3 = (void *)((long)vp2->vp[j] + kvo);
+
+ for (k = 0; k <= VP_IDX3_CNT-1; k++) {
+ pted_allocated++;
+ pa = pmap_steal_avail(sizeof(struct pte_desc),
+ 4, &va);
+ pted = va;
+ vp3->vp[k] = pted;
+ }
+ }
+ }
+
+ pmap_curmaxkvaddr = VM_MAX_KERNEL_ADDRESS;
+
+
+ // XXX should this extend the l2 bootstrap mappings for kernel entries?
+
+ /* now that we have mapping space for everything, lets map it */
+ /* all of these mappings are ram -> kernel va */
+
+ // enable mappings for existing 'allocated' mapping in the bootstrap
+ // page tables
+ extern uint64_t *pagetable;
+ extern int *_end;
+ vp2 = (void *)((long)&pagetable + kvo);
+ struct mem_region *mp;
+ ssize_t size;
+ for (mp = pmap_allocated; mp->size != 0; mp++) {
+ // bounds may be kinda messed up
+ for (pa = mp->start, size = mp->size & ~0xfff;
+ size > 0;
+ pa+= L2_SIZE, size -= L2_SIZE)
+ {
+ paddr_t mappa = pa & ~(L2_SIZE-1);
+ vaddr_t mapva = mappa - kvo;
+ if (mapva < (vaddr_t)&_end)
+ continue;
+ vp2->l2[VP_IDX2(mapva)] = mappa | L2_BLOCK |
+ ATTR_AF| ATTR_IDX(2);
+ }
+ }
+
+ // At this point we are still running on the bootstrap page tables
+ // however all memory allocated for the final page tables is
+ // 'allocated' and should now be mapped
+ // This means we are able to use the virtual addressing to
+ // enter the final mappings into the new mapping tables.
+
+#if 0
+ vm_prot_t prot;
+
+ for (mp = pmap_allocated; mp->size != 0; mp++) {
+ vaddr_t va;
+ paddr_t pa;
+ vsize_t size;
+ extern char *etext();
+ //printf("mapping %08x sz %08x\n", mp->start, mp->size);
+ for (pa = mp->start, va = pa + kvo, size = mp->size & ~0xfff;
+ size > 0;
+ va += PAGE_SIZE, pa+= PAGE_SIZE, size -= PAGE_SIZE)
+ {
+ pa = va - kvo;
+ prot = PROT_READ|PROT_WRITE;
+ if ((vaddr_t)va >= (vaddr_t)kernelstart &&
+ (vaddr_t)va < (vaddr_t)etext)
+ prot |= PROT_EXEC; // XXX remove WRITE?
+ pmap_kenter_cache(va, pa, prot, PMAP_CACHE_WB);
+ }
+ }
+#endif
+ pmap_avail_fixup();
+
+ vstart = pmap_map_stolen(kernelstart);
+
+ void (switch_mmu_kernel)(long);
+ void (*switch_mmu_kernel_table)(long) =
+ (void *)((long)&switch_mmu_kernel + kvo);
+ switch_mmu_kernel_table (pmap_kernel()->pm_pt0pa);
+
+ printf("all mapped\n");
+
+ printf("stolen 0x%x memory\n", arm_kvm_stolen);
+
+ return vstart;
+}
+
+void
+pmap_set_l1(struct pmap *pm, uint64_t va, struct pmapvp1 *l1_va, paddr_t l1_pa)
+{
+ uint64_t pg_entry;
+ int idx0;
+
+ if (l1_pa == 0) {
+ // if this is called from pmap_vp_enter, this is a normally
+ // mapped page, call pmap_extract to get pa
+ pmap_extract(pmap_kernel(), (vaddr_t)l1_va, &l1_pa);
+ }
+
+ if (l1_pa & (Lx_TABLE_ALIGN-1)) {
+ panic("misaligned L2 table\n");
+ }
+
+ pg_entry = VP_Lx(l1_pa);
+
+ idx0 = VP_IDX0(va);
+ pm->pm_vp.l0->vp[idx0] = l1_va;
+
+ pm->pm_vp.l0->l0[idx0] = pg_entry;
+ __asm __volatile("dsb sy");
+
+ dcache_wb_pou((vaddr_t)&pm->pm_vp.l0->l0[idx0], 8);
+
+ ttlb_flush_range(pm, va & PTE_RPGN, 1<<VP_IDX1_POS);
+}
+
+void
+pmap_set_l2(struct pmap *pm, uint64_t va, struct pmapvp2 *l2_va, paddr_t l2_pa)
+{
+ uint64_t pg_entry;
+ struct pmapvp1 *vp1;
+ int idx0, idx1;
+
+ if (l2_pa == 0) {
+ // if this is called from pmap_vp_enter, this is a normally
+ // mapped page, call pmap_extract to get pa
+ pmap_extract(pmap_kernel(), (vaddr_t)l2_va, &l2_pa);
+ }
+
+ if (l2_pa & (Lx_TABLE_ALIGN-1)) {
+ panic("misaligned L2 table\n");
+ }
+
+ pg_entry = VP_Lx(l2_pa);
+
+ idx0 = VP_IDX0(va);
+ idx1 = VP_IDX1(va);
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[idx0];
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+ vp1->vp[idx1] = l2_va;
+ vp1->l1[idx1] = pg_entry;
+
+ __asm __volatile("dsb sy");
+ dcache_wb_pou((vaddr_t)&vp1->l1[idx1], 8);
+
+ ttlb_flush_range(pm, va & PTE_RPGN, 1<<VP_IDX2_POS);
+}
+
+void
+pmap_set_l3(struct pmap *pm, uint64_t va, struct pmapvp3 *l3_va, paddr_t l3_pa)
+{
+ uint64_t pg_entry;
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ int idx0, idx1, idx2;
+
+ if (l3_pa == 0) {
+ // if this is called from pmap_vp_enter, this is a normally
+ // mapped page, call pmap_extract to get pa
+ pmap_extract(pmap_kernel(), (vaddr_t)l3_va, &l3_pa);
+ }
+
+ if (l3_pa & (Lx_TABLE_ALIGN-1)) {
+ panic("misaligned L2 table\n");
+ }
+
+ pg_entry = VP_Lx(l3_pa);
+
+ idx0 = VP_IDX0(va);
+ idx1 = VP_IDX1(va);
+ idx2 = VP_IDX2(va);
+
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[idx0];
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+ vp2 = vp1->vp[idx1];
+
+ vp2->vp[idx2] = l3_va;
+ vp2->l2[idx2] = pg_entry;
+ __asm __volatile("dsb sy");
+ dcache_wb_pou((vaddr_t)&vp2->l2[idx2], 8);
+
+ ttlb_flush_range(pm, va & PTE_RPGN, 1<<VP_IDX3_POS);
+}
+
+/*
+ * activate a pmap entry
+ */
+void
+pmap_activate(struct proc *p)
+{
+ pmap_t pm;
+ struct pcb *pcb;
+ int psw;
+
+ pm = p->p_vmspace->vm_map.pmap;
+ pcb = &p->p_addr->u_pcb;
+
+ // printf("%s: called on proc %p %p\n", __func__, p, pcb->pcb_pagedir);
+ if (pm != pmap_kernel() && pm->pm_asid == -1) {
+ // this userland process has no asid, allocate one.
+ pmap_allocate_asid(pm);
+ }
+
+ if (pm != pmap_kernel())
+ pcb->pcb_pagedir = ((uint64_t)pm->pm_asid << 48) | pm->pm_pt0pa;
+
+ psw = disable_interrupts();
+ if (p == curproc && pm != pmap_kernel() && pm != curcpu()->ci_curpm) {
+ // clean up old process
+ if (curcpu()->ci_curpm != NULL) {
+ atomic_dec_int(&curcpu()->ci_curpm->pm_active);
+ }
+
+ curcpu()->ci_curpm = pm;
+ pmap_setttb(p, pcb->pcb_pagedir, pcb);
+ atomic_inc_int(&pm->pm_active);
+ }
+ restore_interrupts(psw);
+}
+
+/*
+ * deactivate a pmap entry
+ */
+void
+pmap_deactivate(struct proc *p)
+{
+ pmap_t pm;
+ int psw;
+ psw = disable_interrupts();
+ pm = p->p_vmspace->vm_map.pmap;
+ if (pm == curcpu()->ci_curpm) {
+ curcpu()->ci_curpm = NULL;
+ atomic_dec_int(&pm->pm_active);
+ }
+ restore_interrupts(psw);
+}
+
+/*
+ * Get the physical page address for the given pmap/virtual address.
+ */
+boolean_t
+pmap_extract(pmap_t pm, vaddr_t va, paddr_t *pa)
+{
+ struct pte_desc *pted;
+
+ pted = pmap_vp_lookup(pm, va, NULL);
+
+ if (pted == NULL)
+ return FALSE;
+
+ if (pted->pted_pte == 0)
+ return FALSE;
+
+ if (pa != NULL)
+ *pa = (pted->pted_pte & PTE_RPGN) | (va & PAGE_MASK);
+
+ return TRUE;
+}
+
+
+void
+pmap_page_ro(pmap_t pm, vaddr_t va, vm_prot_t prot)
+{
+ struct pte_desc *pted;
+
+ /* Every VA needs a pted, even unmanaged ones. */
+ pted = pmap_vp_lookup(pm, va, NULL);
+ if (!pted || !PTED_VALID(pted)) {
+ return;
+ }
+
+ pted->pted_va &= ~PROT_WRITE;
+ pted->pted_pte &= ~PROT_WRITE;
+ pte_insert(pted);
+
+ ttlb_flush(pm, pted->pted_va & PTE_RPGN);
+
+ return;
+}
+
+/*
+ * Lower the protection on the specified physical page.
+ *
+ * There are only two cases, either the protection is going to 0,
+ * or it is going to read-only.
+ */
+void
+pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
+{
+ int s;
+ struct pte_desc *pted;
+
+ //if (!cold) printf("%s: prot %x\n", __func__, prot);
+
+ /* need to lock for this pv */
+ s = splvm();
+
+ if (prot == PROT_NONE) {
+ while (!LIST_EMPTY(&(pg->mdpage.pv_list))) {
+ pted = LIST_FIRST(&(pg->mdpage.pv_list));
+ pmap_remove_pted(pted->pted_pmap, pted);
+ }
+ /* page is being reclaimed, sync icache next use */
+ atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE);
+ splx(s);
+ return;
+ }
+
+ LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) {
+ pmap_page_ro(pted->pted_pmap, pted->pted_va, prot);
+ }
+ splx(s);
+}
+
+
+void
+pmap_protect(pmap_t pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
+{
+ //if (!cold) printf("%s\n", __func__);
+
+ int s;
+ if (prot & (PROT_READ | PROT_EXEC)) {
+ s = splvm();
+ while (sva < eva) {
+ pmap_page_ro(pm, sva, 0);
+ sva += PAGE_SIZE;
+ }
+ splx(s);
+ return;
+ }
+ pmap_remove(pm, sva, eva);
+}
+
+void
+pmap_init()
+{
+ pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, IPL_VM, 0,
+ "pmap", NULL);
+ pool_setlowat(&pmap_pmap_pool, 2);
+ pool_init(&pmap_pted_pool, sizeof(struct pte_desc), 0, IPL_VM, 0,
+ "pted", NULL);
+ pool_setlowat(&pmap_pted_pool, 20);
+ pool_init(&pmap_vp_pool, sizeof(struct pmapvp2), PAGE_SIZE, IPL_VM, 0,
+ "vp", NULL);
+ //pool_setlowat(&pmap_vp_pool, 20);
+
+ pmap_initialized = 1;
+
+}
+
+void
+pmap_proc_iflush(struct process *pr, vaddr_t addr, vsize_t len)
+{
+ paddr_t pa;
+ vsize_t clen;
+
+ while (len > 0) {
+ /* add one to always round up to the next page */
+ clen = round_page(addr + 1) - addr;
+ if (clen > len)
+ clen = len;
+
+ if (pmap_extract(pr->ps_vmspace->vm_map.pmap, addr, &pa)) {
+ //syncicache((void *)pa, clen);
+ }
+
+ len -= clen;
+ addr += clen;
+ }
+}
+
+
+STATIC uint64_t ap_bits_user [8] = {
+ [PROT_NONE] = ATTR_nG|ATTR_UXN|ATTR_AP(2),
+ [PROT_READ] = ATTR_nG|ATTR_UXN|ATTR_AF|ATTR_AP(3),
+ [PROT_WRITE] = ATTR_nG|ATTR_UXN|ATTR_AF|ATTR_AP(1),
+ [PROT_WRITE|PROT_READ] = ATTR_nG|ATTR_UXN|ATTR_AF|ATTR_AP(1),
+ [PROT_EXEC] = ATTR_nG|ATTR_AF|ATTR_AP(3),
+ [PROT_EXEC|PROT_READ] = ATTR_nG|ATTR_AF|ATTR_AP(3),
+ [PROT_EXEC|PROT_WRITE] = ATTR_nG|ATTR_AF|ATTR_AP(1),
+ [PROT_EXEC|PROT_WRITE|PROT_READ]= ATTR_nG|ATTR_AF|ATTR_AP(1),
+};
+
+STATIC uint64_t ap_bits_kern [8] = {
+ [PROT_NONE] = ATTR_PXN|ATTR_AP(2),
+ [PROT_READ] = ATTR_PXN|ATTR_AF|ATTR_AP(2),
+ [PROT_WRITE] = ATTR_PXN|ATTR_AF|ATTR_AP(0),
+ [PROT_WRITE|PROT_READ] = ATTR_PXN|ATTR_AF|ATTR_AP(0),
+ [PROT_EXEC] = ATTR_AF|ATTR_AP(2),
+ [PROT_EXEC|PROT_READ] = ATTR_AF|ATTR_AP(2),
+ [PROT_EXEC|PROT_WRITE] = ATTR_AF|ATTR_AP(0),
+ [PROT_EXEC|PROT_WRITE|PROT_READ] = ATTR_AF|ATTR_AP(0),
+};
+
+void
+pte_insert(struct pte_desc *pted)
+{
+ /* put entry into table */
+ /* need to deal with ref/change here */
+ uint64_t pte, access_bits;
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ pmap_t pm = pted->pted_pmap;
+ uint64_t attr = 0;
+
+ // see mair in locore.S
+ switch (pted->pted_va & PMAP_CACHE_BITS) {
+ case PMAP_CACHE_WB:
+ attr |= ATTR_IDX(PTE_ATTR_WB); // inner and outer writeback
+ attr |= ATTR_SH(SH_INNER);
+ break;
+ case PMAP_CACHE_WT: /* for the momemnt treating this as uncached */
+ attr |= ATTR_IDX(PTE_ATTR_CI); // inner and outer uncached
+ attr |= ATTR_SH(SH_INNER);
+ break;
+ case PMAP_CACHE_CI:
+ attr |= ATTR_IDX(PTE_ATTR_DEV); // treat as device !?!?!?!
+ break;
+ case PMAP_CACHE_PTE:
+ attr |= ATTR_IDX(PTE_ATTR_CI); // inner and outer uncached, XXX?
+ attr |= ATTR_SH(SH_INNER);
+ break;
+ default:
+ panic("pte_insert:invalid cache mode");
+ }
+
+ // kernel mappings are global, so nG should not be set
+
+ if (pm == pmap_kernel()) {
+ access_bits = ap_bits_kern[pted->pted_pte & PROT_MASK];
+ } else {
+ access_bits = ap_bits_user[pted->pted_pte & PROT_MASK];
+ }
+
+ pte = (pted->pted_pte & PTE_RPGN) | attr | access_bits | L3_P;
+
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[VP_IDX0(pted->pted_va)];
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+ vp2 = vp1->vp[VP_IDX1(pted->pted_va)];
+ if (vp2 == NULL) {
+ panic("have a pted, but missing the l2 for %x va pmap %x",
+ pted->pted_va, pm);
+ }
+ vp3 = vp2->vp[VP_IDX2(pted->pted_va)];
+ if (vp3 == NULL) {
+ panic("have a pted, but missing the l2 for %x va pmap %x",
+ pted->pted_va, pm);
+ }
+ vp3->l3[VP_IDX3(pted->pted_va)] = pte;
+#if 0
+ __asm __volatile("dsb");
+ dcache_wb_pou((vaddr_t)&l2[VP_IDX2(pted->pted_va)], sizeof(l2[VP_IDX2(pted->pted_va)]));
+ //cpu_tlb_flushID_SE(pted->pted_va & PTE_RPGN);
+#endif
+ dcache_wb_pou((vaddr_t) &vp3->l3[VP_IDX3(pted->pted_va)],8);
+ __asm __volatile("dsb sy");
+}
+
+void
+pte_remove(struct pte_desc *pted, int remove_pted)
+{
+ /* put entry into table */
+ /* need to deal with ref/change here */
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ pmap_t pm = pted->pted_pmap;
+
+ if (pm->have_4_level_pt) {
+ vp1 = pm->pm_vp.l0->vp[VP_IDX0(pted->pted_va)];
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+ if (vp1->vp[VP_IDX1(pted->pted_va)] == NULL) {
+ panic("have a pted, but missing the l2 for %x va pmap %x",
+ pted->pted_va, pm);
+ }
+ vp2 = vp1->vp[VP_IDX1(pted->pted_va)];
+ if (vp2 == NULL) {
+ panic("have a pted, but missing the l2 for %x va pmap %x",
+ pted->pted_va, pm);
+ }
+ vp3 = vp2->vp[VP_IDX2(pted->pted_va)];
+ if (vp3 == NULL) {
+ panic("have a pted, but missing the l2 for %x va pmap %x",
+ pted->pted_va, pm);
+ }
+ vp3->l3[VP_IDX3(pted->pted_va)] = 0;
+ if (remove_pted)
+ vp3->vp[VP_IDX3(pted->pted_va)] = NULL;
+ __asm __volatile("dsb sy");
+
+ dcache_wb_pou((vaddr_t)&vp3->l3[VP_IDX3(pted->pted_va)], 8);
+
+ arm64_tlbi_asid(pted->pted_va, pm->pm_asid);
+}
+
+/*
+ * This function exists to do software referenced/modified emulation.
+ * It's purpose is to tell the caller that a fault was generated either
+ * for this emulation, or to tell the caller that it's a legit fault.
+ */
+int pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, int user)
+{
+ struct pte_desc *pted;
+ struct vm_page *pg;
+ paddr_t pa;
+ // pl3 is pointer to the L3 entry to update for this mapping.
+ // will be valid if a pted exists.
+ uint64_t *pl3 = NULL;
+
+ //printf("fault pm %x va %x ftype %x user %x\n", pm, va, ftype, user);
+
+ /* Every VA needs a pted, even unmanaged ones. */
+ pted = pmap_vp_lookup(pm, va, &pl3);
+ if (!pted || !PTED_VALID(pted)) {
+ return 0;
+ }
+
+ /* There has to be a PA for the VA, get it. */
+ pa = (pted->pted_pte & PTE_RPGN);
+
+ /* If it's unmanaged, it must not fault. */
+ pg = PHYS_TO_VM_PAGE(pa);
+ if (pg == NULL) {
+ return 0;
+ }
+
+ /*
+ * Check based on fault type for mod/ref emulation.
+ * if L3 entry is zero, it is not a possible fixup
+ */
+ if (*pl3 == 0)
+ return 0;
+
+
+ /*
+ * Check the fault types to find out if we were doing
+ * any mod/ref emulation and fixup the PTE if we were.
+ */
+ if ((ftype & PROT_WRITE) && /* fault caused by a write */
+ !(pted->pted_pte & PROT_WRITE) && /* and write is disabled now */
+ (pted->pted_va & PROT_WRITE)) { /* but is supposedly allowed */
+
+ /*
+ * Page modified emulation. A write always
+ * includes a reference.
+ */
+ pg->pg_flags |= PG_PMAP_MOD;
+ pg->pg_flags |= PG_PMAP_REF;
+
+ /* Thus, enable read and write. */
+ pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_WRITE));
+
+ pted->pted_pte |= PROT_WRITE;
+ *pl3 &= ~ATTR_AP(2);
+ *pl3 |= ATTR_AF;
+
+ /* Flush tlb. */
+ ttlb_flush(pm, va & PTE_RPGN);
+
+ return 1;
+ } else if ((ftype & PROT_EXEC) && /* fault caused by an exec */
+ !(pted->pted_pte & PROT_EXEC) && /* and exec is disabled now */
+ (pted->pted_va & PROT_EXEC)) { /* but is supposedly allowed */
+
+ /*
+ * Exec always includes a read/reference.
+ */
+ pg->pg_flags |= PG_PMAP_REF;
+
+ /* Thus, enable read and exec. */
+ pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_EXEC));
+ if (pted->pted_pmap == pmap_kernel()) {
+ *pl3 &= ~ATTR_PXN;
+ } else {
+ *pl3 &= ~ATTR_UXN;
+ }
+ *pl3 |= ATTR_AF;
+
+ /* Flush tlb. */
+ ttlb_flush(pm, va & PTE_RPGN);
+
+ return 1;
+ } else if ((ftype & PROT_READ) && /* fault caused by a read */
+ !(pted->pted_pte & PROT_READ) && /* and read is disabled now */
+ (pted->pted_va & PROT_READ)) { /* but is supposedly allowed */
+
+ /*
+ * Page referenced emulation.
+ */
+ pg->pg_flags |= PG_PMAP_REF;
+
+ /* Thus, enable read. */
+ pted->pted_pte |= (pted->pted_va & PROT_READ);
+ *pl3 |= ATTR_AF;
+
+ /* Flush tlb. */
+ ttlb_flush(pm, pted->pted_va & PTE_RPGN);
+
+ return 1;
+ }
+
+ /* didn't catch it, so probably broken */
+ return 0;
+}
+
+void pmap_postinit(void) {}
+void
+pmap_map_section(vaddr_t l1_addr, vaddr_t va, paddr_t pa, int flags, int cache)
+{
+panic("%s called", __func__);
+#if 0
+ uint64_t *l1 = (uint64_t *)l1_addr;
+ uint64_t cache_bits;
+ int ap_flag;
+
+ switch (flags) {
+ case PROT_READ:
+ ap_flag = L1_S_AP2|L1_S_AP0|L1_S_XN;
+ break;
+ case PROT_READ | PROT_WRITE:
+ ap_flag = L1_S_AP0|L1_S_XN;
+ break;
+ }
+
+ switch (cache) {
+ case PMAP_CACHE_WB:
+ cache_bits = L1_MODE_MEMORY;
+ break;
+ case PMAP_CACHE_WT: /* for the momemnt treating this as uncached */
+ cache_bits = L1_MODE_DISPLAY;
+ break;
+ case PMAP_CACHE_CI:
+ cache_bits = L1_MODE_DEV;
+ break;
+ case PMAP_CACHE_PTE:
+ cache_bits = L1_MODE_PTE;
+ break;
+ }
+
+ l1[va>>VP_IDX1_POS] = (pa & L1_S_RPGN) | ap_flag | cache_bits | L1_TYPE_S;
+#endif
+}
+
+void pmap_map_entry(vaddr_t l1, vaddr_t va, paddr_t pa, int i0, int i1) {}
+vsize_t pmap_map_chunk(vaddr_t l1, vaddr_t va, paddr_t pa, vsize_t sz, int prot, int cache)
+{
+ for (; sz > 0; sz -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE) {
+ pmap_kenter_cache(va, pa, prot, cache);
+ }
+ return 0;
+}
+
+
+void pmap_update()
+{
+}
+
+char *memhook;
+vaddr_t zero_page;
+vaddr_t copy_src_page;
+vaddr_t copy_dst_page;
+
+
+int pmap_is_referenced(struct vm_page *pg)
+{
+ return ((pg->pg_flags & PG_PMAP_REF) != 0);
+}
+
+int pmap_is_modified(struct vm_page *pg)
+{
+ return ((pg->pg_flags & PG_PMAP_MOD) != 0);
+}
+
+int pmap_clear_modify(struct vm_page *pg)
+{
+ struct pte_desc *pted;
+ uint64_t *pl3 = NULL;
+
+ //printf("%s\n", __func__);
+ // XXX locks
+ int s;
+
+ s = splvm();
+
+ pg->pg_flags &= ~PG_PMAP_MOD;
+
+ LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) {
+ if (pmap_vp_lookup(pted->pted_pmap, pted->pted_va & PTE_RPGN, &pl3) == NULL)
+ panic("failed to look up pte\n");
+ *pl3 |= ATTR_AP(2);
+ pted->pted_pte &= ~PROT_WRITE;
+
+ ttlb_flush(pted->pted_pmap, pted->pted_va & PTE_RPGN);
+ }
+ splx(s);
+
+ return 0;
+}
+
+/*
+ * When this turns off read permissions it also disables write permissions
+ * so that mod is correctly tracked after clear_ref; FAULT_READ; FAULT_WRITE;
+ */
+int pmap_clear_reference(struct vm_page *pg)
+{
+ struct pte_desc *pted;
+ uint64_t *pl3 = NULL;
+
+ //printf("%s\n", __func__);
+
+ // XXX locks
+ int s;
+
+ s = splvm();
+
+ pg->pg_flags &= ~PG_PMAP_REF;
+
+ LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) {
+ if (pmap_vp_lookup(pted->pted_pmap, pted->pted_va & PTE_RPGN, &pl3) == NULL)
+ panic("failed to look up pte\n");
+ pted->pted_pte &= ~PROT_MASK;
+ *pl3 |= ATTR_AP(2); // turns of write as well !?!?
+ *pl3 &= ~ATTR_AF;
+ pted->pted_pte &= ~PROT_WRITE|PROT_READ;
+
+ ttlb_flush(pted->pted_pmap, pted->pted_va & PTE_RPGN);
+ }
+ splx(s);
+
+ return 0;
+}
+
+void pmap_copy(pmap_t src_pmap, pmap_t dst_pmap, vaddr_t src, vsize_t sz, vaddr_t dst)
+{
+ //printf("%s\n", __func__);
+}
+
+void pmap_unwire(pmap_t pm, vaddr_t va)
+{
+ struct pte_desc *pted;
+
+ //printf("%s\n", __func__);
+
+ pted = pmap_vp_lookup(pm, va, NULL);
+ if ((pted != NULL) && (pted->pted_va & PTED_VA_WIRED_M)) {
+ pm->pm_stats.wired_count--;
+ pted->pted_va &= ~PTED_VA_WIRED_M;
+ }
+}
+
+void pmap_remove_holes(struct vmspace *vm)
+{
+ /* NOOP */
+}
+
+void pmap_virtual_space(vaddr_t *start, vaddr_t *end)
+{
+ *start = virtual_avail;
+ *end = virtual_end;
+}
+
+vaddr_t pmap_curmaxkvaddr;
+
+void pmap_avail_fixup(void);
+
+void
+pmap_setup_avail( uint64_t ram_start, uint64_t ram_end, uint64_t kvo)
+{
+ /* This makes several assumptions
+ * 1) kernel will be located 'low' in memory
+ * 2) memory will not start at VM_MIN_KERNEL_ADDRESS
+ * 3) several MB of memory starting just after the kernel will
+ * be premapped at the kernel address in the bootstrap mappings
+ * 4) kvo will be the 64 bit number to add to the ram address to
+ * obtain the kernel virtual mapping of the ram. KVO == PA -> VA
+ * 5) it is generally assumed that these translations will occur with
+ * large granularity, at minimum the translation will be page
+ * aligned, if not 'section' or greater.
+ */
+
+ pmap_avail_kvo = kvo;
+ pmap_avail[0].start = ram_start;
+ pmap_avail[0].size = ram_end-ram_start;
+
+
+ // XXX - support more than one region
+ pmap_memregions[0].start = ram_start;
+ pmap_memregions[0].end = ram_end;
+ pmap_memcount = 1;
+
+ /* XXX - multiple sections */
+ physmem = atop(pmap_avail[0].size);
+
+ pmap_cnt_avail = 1;
+
+ pmap_avail_fixup();
+}
+
+void
+pmap_avail_fixup(void)
+{
+ struct mem_region *mp;
+ vaddr_t align;
+ vaddr_t end;
+
+ mp = pmap_avail;
+ while(mp->size !=0) {
+ align = round_page(mp->start);
+ if (mp->start != align) {
+ pmap_remove_avail(mp->start, align);
+ mp = pmap_avail;
+ continue;
+ }
+ end = mp->start+mp->size;
+ align = trunc_page(end);
+ if (end != align) {
+ pmap_remove_avail(align, end);
+ mp = pmap_avail;
+ continue;
+ }
+ mp++;
+ }
+}
+
+/* remove a given region from avail memory */
+void
+pmap_remove_avail(paddr_t base, paddr_t end)
+{
+ struct mem_region *mp;
+ int i;
+ long mpend;
+
+ /* remove given region from available */
+ for (mp = pmap_avail; mp->size; mp++) {
+ /*
+ * Check if this region holds all of the region
+ */
+ mpend = mp->start + mp->size;
+ if (base > mpend) {
+ continue;
+ }
+ if (base <= mp->start) {
+ if (end <= mp->start)
+ break; /* region not present -??? */
+
+ if (end >= mpend) {
+ /* covers whole region */
+ /* shorten */
+ for (i = mp - pmap_avail;
+ i < pmap_cnt_avail;
+ i++) {
+ pmap_avail[i] = pmap_avail[i+1];
+ }
+ pmap_cnt_avail--;
+ pmap_avail[pmap_cnt_avail].size = 0;
+ } else {
+ mp->start = end;
+ mp->size = mpend - end;
+ }
+ } else {
+ /* start after the beginning */
+ if (end >= mpend) {
+ /* just truncate */
+ mp->size = base - mp->start;
+ } else {
+ /* split */
+ for (i = pmap_cnt_avail;
+ i > (mp - pmap_avail);
+ i--) {
+ pmap_avail[i] = pmap_avail[i - 1];
+ }
+ pmap_cnt_avail++;
+ mp->size = base - mp->start;
+ mp++;
+ mp->start = end;
+ mp->size = mpend - end;
+ }
+ }
+ }
+ for (mp = pmap_allocated; mp->size != 0; mp++) {
+ if (base < mp->start) {
+ if (end == mp->start) {
+ mp->start = base;
+ mp->size += end - base;
+ break;
+ }
+ /* lengthen */
+ for (i = pmap_cnt_allocated; i > (mp - pmap_allocated);
+ i--) {
+ pmap_allocated[i] = pmap_allocated[i - 1];
+ }
+ pmap_cnt_allocated++;
+ mp->start = base;
+ mp->size = end - base;
+ return;
+ }
+ if (base == (mp->start + mp->size)) {
+ mp->size += end - base;
+ return;
+ }
+ }
+ if (mp->size == 0) {
+ mp->start = base;
+ mp->size = end - base;
+ pmap_cnt_allocated++;
+ }
+}
+
+/* XXX - this zeros pages via their physical address */
+paddr_t
+pmap_steal_avail(size_t size, int align, void **kva)
+{
+ struct mem_region *mp;
+ long start;
+ long remsize;
+ arm_kvm_stolen += size; // debug only
+
+ for (mp = pmap_avail; mp->size; mp++) {
+ if (mp->size > size) {
+ start = (mp->start + (align -1)) & ~(align -1);
+ remsize = mp->size - (start - mp->start);
+ if (remsize >= 0) {
+ pmap_remove_avail(start, start+size);
+ if (kva != NULL){
+ *kva = (void *)(start - pmap_avail_kvo);
+ }
+ bzero((void*)(start), size);
+ return start;
+ }
+ }
+ }
+ panic ("unable to allocate region with size %x align %x",
+ size, align);
+ return 0; // XXX - only here because of ifdef
+}
+
+vaddr_t
+pmap_map_stolen(vaddr_t kernel_start)
+{
+ int prot;
+ struct mem_region *mp;
+ uint64_t pa, va, e;
+ extern char *etext();
+
+
+ int oldprot = 0;
+ printf("mapping self\n");
+ for (mp = pmap_allocated; mp->size; mp++) {
+ printf("start %16llx end %16llx\n", mp->start, mp->start + mp->size);
+ printf("exe range %16llx %16llx\n", kernel_start,
+ (uint64_t)&etext);
+ for (e = 0; e < mp->size; e += PAGE_SIZE) {
+ /* XXX - is this a kernel text mapping? */
+ /* XXX - Do we care about KDB ? */
+ pa = mp->start + e;
+ va = pa - pmap_avail_kvo;
+ if ((vaddr_t)va >= (vaddr_t)kernel_start &&
+ (vaddr_t)va < (vaddr_t)&etext) {
+ prot = PROT_READ|PROT_WRITE|
+ PROT_EXEC;
+ } else {
+ prot = PROT_READ|PROT_WRITE;
+ }
+ if (prot != oldprot) {
+ printf("mapping v %16llx p %16llx prot %x\n", va,
+ pa, prot);
+ oldprot = prot;
+ }
+ pmap_kenter_cache(va, pa, prot, PMAP_CACHE_WB);
+ }
+ }
+ printf("last mapping v %16llx p %16llx\n", va, pa);
+ return va + PAGE_SIZE;
+ return 0;
+}
+
+void
+pmap_physload_avail(void)
+{
+ struct mem_region *mp;
+ uint64_t start, end;
+
+ for (mp = pmap_avail; mp->size; mp++) {
+ if (mp->size < PAGE_SIZE) {
+ printf(" skipped - too small\n");
+ continue;
+ }
+ start = mp->start;
+ if (start & PAGE_MASK) {
+ start = PAGE_SIZE + (start & PMAP_PA_MASK);
+ }
+ end = mp->start + mp->size;
+ if (end & PAGE_MASK) {
+ end = (end & PMAP_PA_MASK);
+ }
+ uvm_page_physload(atop(start), atop(end),
+ atop(start), atop(end), 0);
+
+ }
+}
+void
+pmap_show_mapping(uint64_t va)
+{
+ struct pmapvp1 *vp1;
+ struct pmapvp2 *vp2;
+ struct pmapvp3 *vp3;
+ struct pte_desc *pted;
+ printf("showing mapping of %llx\n", va);
+ struct pmap *pm;
+ if (va & 1ULL << 63) {
+ pm = pmap_kernel();
+ } else {
+ pm = curproc->p_vmspace->vm_map.pmap;
+ }
+
+ if (pm->have_4_level_pt) {
+ printf(" vp0 = %llx off %x\n", pm->pm_vp.l0, VP_IDX0(va)*8);
+ vp1 = pm->pm_vp.l0->vp[VP_IDX0(va)];
+ if (vp1 == NULL) {
+ return;
+ }
+ } else {
+ vp1 = pm->pm_vp.l1;
+ }
+ uint64_t ttbr0, tcr;
+ __asm volatile ("mrs %x0, ttbr0_el1" : "=r"(ttbr0));
+ __asm volatile ("mrs %x0, tcr_el1" : "=r"(tcr));
+
+ printf(" ttbr0 %llx %llx %llx tcr %llx\n", ttbr0, pm->pm_pt0pa);
+ printf(" vp1 = %llx \n", vp1, VP_IDX1(va) * 8);
+
+
+ vp2 = vp1->vp[VP_IDX1(va)];
+ printf(" vp2 = %llx lp2 = %llx idx1 off %x\n",
+ vp2, vp1->l1[VP_IDX1(va)], VP_IDX1(va)*8);
+ if (vp2 == NULL) {
+ return;
+ }
+
+ vp3 = vp2->vp[VP_IDX2(va)];
+ printf(" vp3 = %llx lp3 = %llx idx2 off %x\n",
+ vp3, vp2->l2[VP_IDX2(va)], VP_IDX2(va)*8);
+ if (vp3 == NULL) {
+ return;
+ }
+
+ pted = vp3->vp[VP_IDX3(va)];
+ printf(" pted = %p lp3 = %llx idx3 off %x\n",
+ pted, vp3->l3[VP_IDX3(va)], VP_IDX3(va)*8);
+
+ return;
+}
+
+// in theory arm64 can support 16 bit asid should we support more?
+// XXX should this be based on how many the specific cpu supports.
+#define MAX_ASID 256
+struct pmap *pmap_asid[MAX_ASID];
+int pmap_asid_id_next = 1;
+
+// stupid quick allocator, flush all asid when we run out
+// XXX never searches, just flushes all on rollover (or out)
+// XXXXX - this is not MP safe
+// MPSAFE would need to check if slot is available, and skip if
+// not and on revoking asids it would need to lock each pmap, see if it were
+// active, if not active, free the asid, mark asid free , and then unlock
+void
+pmap_allocate_asid(pmap_t pm)
+{
+ int i, new_asid;
+
+ if (pmap_asid_id_next == MAX_ASID) {
+ // out of asid, flush all
+ __asm __volatile("tlbi vmalle1is");
+ for (i = 0;i < MAX_ASID; i++) {
+ if (pmap_asid[i] != NULL) {
+ // printf("reclaiming asid %d from %p\n", i,
+ // pmap_asid[i] );
+ pmap_asid[i]->pm_asid = -1;
+ pmap_asid[i] = NULL;
+ }
+ }
+ pmap_asid_id_next = 1;
+ }
+
+ // locks?
+ new_asid = pmap_asid_id_next++;
+
+ //printf("%s: allocating asid %d for pmap %p\n",
+ // __func__, new_asid, pm);
+
+ pmap_asid[new_asid] = pm;
+ pmap_asid[new_asid]->pm_asid = new_asid;
+ return;
+}
+
+void
+pmap_free_asid(pmap_t pm)
+{
+ //printf("freeing asid %d pmap %p\n", pm->pm_asid, pm);
+ // XX locks
+ int asid = pm->pm_asid;
+ pm->pm_asid = -1;
+ pmap_asid[asid] = NULL;
+}
+
+void
+pmap_setttb(struct proc *p, paddr_t pagedir, struct pcb *pcb)
+{
+ // XXX process locks
+ pmap_t pm = p->p_vmspace->vm_map.pmap;
+ //int oasid = pm->pm_asid;
+
+ if (pm != pmap_kernel()) {
+ if (pm->pm_asid < 0) {
+ pmap_allocate_asid(pm);
+ pcb->pcb_pagedir = ((uint64_t)pm->pm_asid << 48) |
+ pm->pm_pt0pa;
+ pagedir = pcb->pcb_pagedir;
+ }
+ //printf("switching userland to %p %p asid %d new asid %d\n",
+ // pm, pmap_kernel(), oasid, pm->pm_asid);
+ }
+
+ __asm volatile ("msr ttbr0_el1, %x0" :: "r"(pagedir));
+}
diff --git a/sys/arch/arm64/arm64/process_machdep.c b/sys/arch/arm64/arm64/process_machdep.c
new file mode 100644
index 00000000000..9665e40a5f8
--- /dev/null
+++ b/sys/arch/arm64/arm64/process_machdep.c
@@ -0,0 +1,93 @@
+/* $OpenBSD: process_machdep.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+/*
+ * This file may seem a bit stylized, but that so that it's easier to port.
+ * Functions to be implemented here are:
+ *
+ * process_read_regs(proc, regs)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_regs is called.
+ *
+ * process_write_regs(proc, regs)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_regs is called.
+ *
+ * process_sstep(proc, sstep)
+ * Arrange for the process to trap or not trap depending on sstep
+ * after executing a single instruction.
+ *
+ * process_set_pc(proc)
+ * Set the process's program counter.
+ */
+
+#include <sys/param.h>
+
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+
+#include <machine/pcb.h>
+#include <machine/reg.h>
+
+#include <arm64/armreg.h>
+
+int
+process_read_regs(struct proc *p, struct reg *regs)
+{
+ return(0);
+}
+
+int
+process_read_fpregs(struct proc *p, struct fpreg *regs)
+{
+ return(0);
+}
+
+#ifdef PTRACE
+
+int
+process_write_regs(struct proc *p, struct reg *regs)
+{
+ return(0);
+}
+
+int
+process_write_fpregs(struct proc *p, struct fpreg *regs)
+{
+ return(0);
+}
+
+int
+process_sstep(struct proc *p, int sstep)
+{
+ if (sstep)
+ return (EINVAL);
+ return 0;
+}
+
+int
+process_set_pc(struct proc *p, caddr_t addr)
+{
+ return (0);
+}
+
+#endif /* PTRACE */
diff --git a/sys/arch/arm64/arm64/sig_machdep.c b/sys/arch/arm64/arm64/sig_machdep.c
new file mode 100644
index 00000000000..d1c50436c87
--- /dev/null
+++ b/sys/arch/arm64/arm64/sig_machdep.c
@@ -0,0 +1,217 @@
+/* $OpenBSD: sig_machdep.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*
+ * Copyright (c) 2001 Opsycon AB (www.opsycon.se)
+ *
+ * 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 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/mount.h> /* XXX only needed by syscallargs.h */
+#include <sys/proc.h>
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/syscallargs.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+
+#include <arm64/armreg.h>
+
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/pcb.h>
+
+static __inline struct trapframe *
+process_frame(struct proc *p)
+{
+ return p->p_addr->u_pcb.pcb_tf;
+}
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * in u. to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user specified pc.
+ */
+void
+sendsig(sig_t catcher, int sig, int returnmask, u_long code, int type,
+ union sigval val)
+{
+ struct proc *p = curproc;
+ struct sigframe *fp, ksf;
+ struct trapframe *tf;
+ struct sigacts *psp = p->p_p->ps_sigacts;
+ siginfo_t *sip;
+ int fsize;
+ int i;
+
+ tf = process_frame(p);
+
+ /*
+ * Allocate space for the signal handler context.
+ */
+ fsize = sizeof(struct sigframe);
+ if (!(psp->ps_siginfo & sigmask(sig)))
+ fsize -= sizeof(siginfo_t);
+ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
+ !sigonstack(tf->tf_sp) && (psp->ps_sigonstack & sigmask(sig)))
+ fp = (struct sigframe *)(p->p_sigstk.ss_sp +
+ p->p_sigstk.ss_size - fsize);
+ else
+ fp = (struct sigframe *)(tf->tf_sp - fsize);
+
+ fp = (struct sigframe *)STACKALIGN(fp);
+
+ bzero (&ksf, sizeof(ksf));
+ ksf.sf_signum = sig;
+ sip = NULL;
+
+ for (i=0; i <= 30; i++) {
+ ksf.sf_sc.sc_x[i] = tf->tf_x[i];
+ }
+ ksf.sf_sc.sc_sp = tf->tf_sp;
+ ksf.sf_sc.sc_lr = tf->tf_lr;
+ ksf.sf_sc.sc_elr = tf->tf_elr;
+ ksf.sf_sc.sc_spsr = tf->tf_spsr;
+
+ // Save signal mask.
+ ksf.sf_sc.sc_mask = returnmask;
+
+ if (psp->ps_siginfo & sigmask(sig)) {
+ sip = &fp->sf_si;
+ initsiginfo(&ksf.sf_si, sig, code, type, val);
+ }
+
+ // XXX copy floating point context
+ if (copyout(&ksf, fp, fsize ) != 0) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ sigexit(p, SIGILL);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Build the argument list for the signal handler.
+ */
+
+ tf->tf_x[0] = sig;
+ tf->tf_x[1] = (register_t)sip;
+ tf->tf_x[2] = (register_t)&fp->sf_sc;
+ tf->tf_lr = p->p_p->ps_sigcode;
+ tf->tf_elr = (register_t)catcher;
+ tf->tf_sp = (register_t)fp;
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psr to gain improper privileges or to cause
+ * a machine fault.
+ */
+
+int
+sys_sigreturn(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_sigreturn_args /* {
+ syscallarg(struct sigcontext *) sigcntxp;
+ } */ *uap = v;
+ struct sigcontext *scp, ksc;
+ struct trapframe *tf;
+ int i;
+
+ scp = SCARG(uap, sigcntxp);
+ if (copyin((caddr_t)scp, &ksc, sizeof(*scp)) != 0)
+ return (EFAULT);
+
+ /*
+ * Make sure the processor mode has not been tampered with and
+ * interrupts have not been disabled.
+ */
+ if ((ksc.sc_spsr & PSR_M_MASK) != PSR_M_EL0t ||
+ (ksc.sc_spsr & (PSR_I | PSR_F)) != 0)
+ return (EINVAL);
+
+ /* Restore register context. */
+ tf = process_frame(p);
+ for (i=0; i <= 30; i++) {
+ tf->tf_x[i] = ksc.sc_x[i];
+ }
+ tf->tf_sp = ksc.sc_sp;
+ tf->tf_lr = ksc.sc_lr;
+ tf->tf_elr = ksc.sc_elr;
+ tf->tf_spsr = ksc.sc_spsr;
+
+ /* Restore signal mask. */
+ p->p_sigmask = ksc.sc_mask & ~sigcantmask;
+
+ // XXX fpustate
+
+ return (EJUSTRETURN);
+}
diff --git a/sys/arch/arm64/arm64/softintr.c b/sys/arch/arm64/arm64/softintr.c
new file mode 100644
index 00000000000..b4f0ffc0967
--- /dev/null
+++ b/sys/arch/arm64/arm64/softintr.c
@@ -0,0 +1,196 @@
+/* $OpenBSD: softintr.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: softintr.c,v 1.1 2003/02/26 21:26:12 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Generic soft interrupt implementation
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+
+#include <machine/intr.h>
+
+#include <uvm/uvm_extern.h>
+
+struct soft_intr soft_intrs[SI_NSOFTINTR];
+
+const int soft_intr_to_ssir[SI_NSOFTINTR] = {
+ SIR_SOFT,
+ SIR_CLOCK,
+ SIR_NET,
+ SIR_TTY,
+};
+
+void softintr_biglock_wrap(void *);
+
+/*
+ * softintr_init:
+ *
+ * Initialize the software interrupt system.
+ */
+void
+softintr_init(void)
+{
+ struct soft_intr *si;
+ int i;
+
+ for (i = 0; i < SI_NSOFTINTR; i++) {
+ si = &soft_intrs[i];
+ TAILQ_INIT(&si->softintr_q);
+ mtx_init(&si->softintr_lock, IPL_HIGH);
+ si->softintr_ssir = soft_intr_to_ssir[i];
+ }
+}
+
+/*
+ * softintr_dispatch:
+ *
+ * Process pending software interrupts.
+ */
+void
+softintr_dispatch(int which)
+{
+ struct soft_intr *si = &soft_intrs[which];
+ struct soft_intrhand *sih;
+ void *arg;
+ void (*fn)(void *);
+
+ for (;;) {
+ mtx_enter(&si->softintr_lock);
+ sih = TAILQ_FIRST(&si->softintr_q);
+ if (sih == NULL) {
+ mtx_leave(&si->softintr_lock);
+ break;
+ }
+ TAILQ_REMOVE(&si->softintr_q, sih, sih_q);
+ sih->sih_pending = 0;
+
+ uvmexp.softs++;
+ arg = sih->sih_arg;
+ fn = sih->sih_fn;
+ mtx_leave(&si->softintr_lock);
+
+ (*fn)(arg);
+ }
+}
+
+#ifdef MULTIPROCESSOR
+void
+softintr_biglock_wrap(void *arg)
+{
+ struct soft_intrhand *sih = arg;
+
+ KERNEL_LOCK();
+ sih->sih_fnwrap(sih->sih_argwrap);
+ KERNEL_UNLOCK();
+}
+#endif
+
+/*
+ * softintr_establish: [interface]
+ *
+ * Register a software interrupt handler.
+ */
+void *
+softintr_establish_flags(int ipl, void (*func)(void *), void *arg, int flags)
+{
+ struct soft_intr *si;
+ struct soft_intrhand *sih;
+ int which;
+
+ switch (ipl) {
+ case IPL_SOFTCLOCK:
+ which = SIR_CLOCK;
+ break;
+
+ case IPL_SOFTNET:
+ which = SIR_NET;
+ break;
+
+ case IPL_TTY:
+ case IPL_SOFTTTY:
+ which = SIR_TTY;
+ break;
+
+ default:
+ panic("softintr_establish");
+ }
+
+ si = &soft_intrs[which];
+
+ sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (__predict_true(sih != NULL)) {
+ sih->sih_intrhead = si;
+#ifdef MULTIPROCESSOR
+ if (flags & SOFTINTR_ESTABLISH_MPSAFE) {
+#endif
+ sih->sih_fn = func;
+ sih->sih_arg = arg;
+#ifdef MULTIPROCESSOR
+ } else {
+ sih->sih_fnwrap = func;
+ sih->sih_argwrap = arg;
+ sih->sih_fn = softintr_biglock_wrap;
+ sih->sih_arg = sih;
+ }
+#endif
+ }
+ return (sih);
+}
+
+/*
+ * softintr_disestablish: [interface]
+ *
+ * Unregister a software interrupt handler.
+ */
+void
+softintr_disestablish(void *arg)
+{
+ struct soft_intrhand *sih = arg;
+ struct soft_intr *si = sih->sih_intrhead;
+
+ mtx_enter(&si->softintr_lock);
+ if (sih->sih_pending) {
+ TAILQ_REMOVE(&si->softintr_q, sih, sih_q);
+ sih->sih_pending = 0;
+ }
+ mtx_leave(&si->softintr_lock);
+
+ free(sih, M_DEVBUF, 0);
+}
+
+void
+softintr(int intrq)
+{
+ // protected by mutex in caller
+ curcpu()->ci_ipending |= (1 << intrq);
+}
diff --git a/sys/arch/arm64/arm64/support.S b/sys/arch/arm64/arm64/support.S
new file mode 100644
index 00000000000..7167ff2b0a9
--- /dev/null
+++ b/sys/arch/arm64/arm64/support.S
@@ -0,0 +1,255 @@
+/* $OpenBSD: support.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * Copyright (c) 2014-2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Andrew Turner
+ * under sponsorship from the FreeBSD Foundation
+ *
+ * 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 <machine/asm.h>
+
+#include <machine/setjmp.h>
+
+#include "assym.h"
+
+/*
+ * One of the fu* or su* functions failed, return -1.
+ */
+ENTRY(fsu_fault)
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */
+ mov x0, #-1
+ ret
+END(fsu_fault)
+
+/*
+ * int casueword32(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
+ */
+ENTRY(casueword32)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x4) /* And set it */
+1: ldxr w4, [x0] /* Load-exclusive the data */
+ cmp w4, w1 /* Compare */
+ b.ne 2f /* Not equal, exit */
+ stxr w5, w3, [x0] /* Store the new data */
+ cbnz w5, 1b /* Retry on failure */
+ ldrb w0, [x0] /* Try loading the data */
+2: SET_FAULT_HANDLER(xzr, x5) /* Reset the fault handler */
+ str w4, [x2] /* Store the read data */
+ ret /* Return */
+END(casueword32)
+
+/*
+ * int casueword(volatile u_long *, u_long, u_long *, u_long)
+ */
+ENTRY(casueword)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x4) /* And set it */
+1: ldxr x4, [x0] /* Load-exclusive the data */
+ cmp x4, x1 /* Compare */
+ b.ne 2f /* Not equal, exit */
+ stxr w5, x3, [x0] /* Store the new data */
+ cbnz w5, 1b /* Retry on failure */
+ ldrb w0, [x0] /* Try loading the data */
+2: SET_FAULT_HANDLER(xzr, x5) /* Reset the fault handler */
+ str x4, [x2] /* Store the read data */
+ ret /* Return */
+END(casueword)
+
+/*
+ * int fubyte(volatile const void *)
+ */
+ENTRY(fubyte)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x1) /* And set it */
+ ldrb w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */
+ ret /* Return */
+END(fubyte)
+
+/*
+ * int fuword(volatile const void *)
+ */
+ENTRY(fuword16)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x1) /* And set it */
+ ldrh w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */
+ ret /* Return */
+END(fuword16)
+
+/*
+ * int32_t fueword32(volatile const void *, int32_t *)
+ */
+ENTRY(fueword32)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ ldr w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ str w0, [x1] /* Save the data in kernel space */
+ mov w0, #0 /* Success */
+ ret /* Return */
+END(fueword32)
+
+/*
+ * long fueword(volatile const void *, int64_t *)
+ * int64_t fueword64(volatile const void *, int64_t *)
+ */
+ENTRY(fueword)
+EENTRY(fueword64)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ ldr x0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ str x0, [x1] /* Save the data in kernel space */
+ mov x0, #0 /* Success */
+ ret /* Return */
+EEND(fueword64)
+END(fueword)
+
+/*
+ * int subyte(volatile void *, int)
+ */
+ENTRY(subyte)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ strb w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(subyte)
+
+/*
+ * int suword16(volatile void *, int)
+ */
+ENTRY(suword16)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ strh w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(suword16)
+
+/*
+ * int suword32(volatile void *, int)
+ */
+ENTRY(suword32)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ str w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(suword32)
+
+/*
+ * int suword(volatile void *, long)
+ */
+ENTRY(suword)
+EENTRY(suword64)
+ adr x6, fsu_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ str x1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+EEND(suword64)
+END(suword)
+
+/*
+ * fuswintr and suswintr are just like fusword and susword except that if
+ * the page is not in memory or would cause a trap, then we return an error.
+ * The important thing is to prevent sleep() and switch().
+ */
+
+/*
+ * Special handler so the trap code knows not to sleep.
+ */
+ENTRY(fsu_intr_fault)
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */
+ mov x0, #-1
+ ret
+END(fsu_fault)
+
+/*
+ * int fuswintr(void *)
+ */
+ENTRY(fuswintr)
+ adr x6, fsu_intr_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x1) /* And set it */
+ ldr w0, [x0] /* Try loading the data */
+ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */
+ ret /* Return */
+END(fuswintr)
+
+/*
+ * int suswintr(void *base, int word)
+ */
+ENTRY(suswintr)
+ adr x6, fsu_intr_fault /* Load the fault handler */
+ SET_FAULT_HANDLER(x6, x2) /* And set it */
+ str w1, [x0] /* Try storing the data */
+ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */
+ mov x0, #0 /* Success */
+ ret /* Return */
+END(suswintr)
+
+ENTRY(setjmp)
+ /* Store the stack pointer */
+ mov x8, sp
+ str x8, [x0]
+
+ /* Store the general purpose registers and lr */
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, lr, [x0], #16
+
+ /* Return value */
+ mov x0, #0
+ ret
+END(setjmp)
+
+ENTRY(longjmp)
+ /* Restore the stack pointer */
+ ldr x8, [x0], #8
+ mov sp, x8
+
+ /* Restore the general purpose registers and lr */
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, lr, [x0], #16
+
+ /* Load the return value */
+ mov x0, x1
+ ret
+END(longjmp)
diff --git a/sys/arch/arm64/arm64/sys_machdep.c b/sys/arch/arm64/arm64/sys_machdep.c
new file mode 100644
index 00000000000..7e41f69d64d
--- /dev/null
+++ b/sys/arch/arm64/arm64/sys_machdep.c
@@ -0,0 +1,71 @@
+/* $OpenBSD: sys_machdep.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sys_machdep.c 8.1 (Berkeley) 6/10/93
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/buf.h>
+
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+
+#include <uvm/uvm_extern.h>
+
+int
+sys_sysarch(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_sysarch_args /* {
+ syscallarg(int) op;
+ syscallarg(void *) parms;
+ } */ *uap = v;
+ int error = 0;
+
+ switch(SCARG(uap, op)) {
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
diff --git a/sys/arch/arm64/arm64/syscall.c b/sys/arch/arm64/arm64/syscall.c
new file mode 100644
index 00000000000..a497cd74e74
--- /dev/null
+++ b/sys/arch/arm64/arm64/syscall.c
@@ -0,0 +1,134 @@
+/* $OpenBSD: syscall.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/user.h>
+#include <sys/vnode.h>
+#include <sys/signal.h>
+#include <sys/syscall.h>
+#include <sys/syscall_mi.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/vfp.h>
+
+#define MAXARGS 8
+
+void
+svc_handler(trapframe_t *frame)
+{
+ struct proc *p = curproc;
+ const struct sysent *callp;
+ int code, error;
+ u_int nap = 8, nargs;
+ register_t *ap, *args, copyargs[MAXARGS], rval[2];
+
+ uvmexp.syscalls++;
+
+ /* Before enabling interrupts, save FPU state */
+ vfp_save();
+
+ /* Re-enable interrupts if they were enabled previously */
+ if (__predict_true((frame->tf_spsr & I_bit) == 0))
+ enable_interrupts();
+
+ p->p_addr->u_pcb.pcb_tf = frame;
+
+ code = frame->tf_x[8];
+
+ ap = &frame->tf_x[0];
+ callp = p->p_p->ps_emul->e_sysent;
+
+ switch (code) {
+ case SYS_syscall:
+ code = *ap++;
+ nap--;
+ break;
+ case SYS___syscall:
+ code = *ap++;
+ nap--;
+ break;
+ }
+
+ if (code < 0 || code >= p->p_p->ps_emul->e_nsysent) {
+ callp += p->p_p->ps_emul->e_nosys;
+ } else {
+ callp += code;
+ }
+ nargs = callp->sy_argsize / sizeof(register_t);
+ if (nargs <= nap) {
+ args = ap;
+ } else {
+ KASSERT(nargs <= MAXARGS);
+ memcpy(copyargs, ap, nap * sizeof(register_t));
+ if ((error = copyin((void *)frame->tf_sp, copyargs + nap,
+ (nargs - nap) * sizeof(register_t))))
+ goto bad;
+ args = copyargs;
+ }
+
+ rval[0] = 0;
+ rval[1] = frame->tf_x[1];
+
+ error = mi_syscall(p, code, callp, args, rval);
+
+ switch (error) {
+ case 0:
+ frame->tf_x[0] = rval[0];
+ frame->tf_x[1] = rval[1];
+
+ frame->tf_spsr &= ~PSR_C; /* carry bit */
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct the pc to point at the swi.
+ */
+ frame->tf_elr -= 4;
+ break;
+
+ case EJUSTRETURN:
+ /* nothing to do */
+ break;
+
+ default:
+ bad:
+ frame->tf_x[0] = error;
+ frame->tf_spsr |= PSR_C; /* carry bit */
+ break;
+ }
+
+ mi_syscall_return(p, code, error, rval);
+}
+
+void
+child_return(arg)
+ void *arg;
+{
+ struct proc *p = arg;
+ struct trapframe *frame = p->p_addr->u_pcb.pcb_tf;
+
+ frame->tf_x[0] = 0;
+ frame->tf_x[1] = 1;
+ frame->tf_spsr &= ~PSR_C; /* carry bit */
+
+ mi_child_return(p);
+}
diff --git a/sys/arch/arm64/arm64/trap.c b/sys/arch/arm64/arm64/trap.c
new file mode 100644
index 00000000000..3f505e52791
--- /dev/null
+++ b/sys/arch/arm64/arm64/trap.c
@@ -0,0 +1,334 @@
+/* $OpenBSD: trap.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <sys/signalvar.h>
+
+#ifdef KDB
+#include <sys/kdb.h>
+#endif
+
+#include <uvm/uvm.h>
+#include <uvm/uvm_extern.h>
+
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <machine/cpu.h>
+#include <machine/vmparam.h>
+
+#include <machine/vfp.h>
+
+#ifdef KDB
+#include <machine/db_machdep.h>
+#endif
+
+#ifdef DDB
+#include <ddb/db_output.h>
+#endif
+
+extern register_t fsu_intr_fault;
+
+/* Called from exception.S */
+void do_el1h_sync(struct trapframe *);
+void do_el0_sync(struct trapframe *);
+void do_el0_error(struct trapframe *);
+
+
+#if 0
+int
+cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
+{
+ struct proc *p;
+ register_t *ap;
+ int nap;
+
+ nap = 8;
+ p = td->td_proc;
+ ap = td->td_frame->tf_x;
+
+ sa->code = td->td_frame->tf_x[8];
+
+ if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
+ sa->code = *ap++;
+ nap--;
+ }
+
+ if (p->p_sysent->sv_mask)
+ sa->code &= p->p_sysent->sv_mask;
+ if (sa->code >= p->p_sysent->sv_size)
+ sa->callp = &p->p_sysent->sv_table[0];
+ else
+ sa->callp = &p->p_sysent->sv_table[sa->code];
+
+ sa->narg = sa->callp->sy_narg;
+ memcpy(sa->args, ap, nap * sizeof(register_t));
+ if (sa->narg > nap)
+ panic("TODO: Could we have more then 8 args?");
+
+ td->td_retval[0] = 0;
+ td->td_retval[1] = 0;
+
+ return (0);
+}
+
+#include "../../kern/subr_syscall.c"
+
+static void
+svc_handler(struct trapframe *frame)
+{
+ struct syscall_args sa;
+ struct thread *td;
+ int error;
+
+ td = curthread;
+ td->td_frame = frame;
+
+ error = syscallenter(td, &sa);
+ syscallret(td, error, &sa);
+}
+#endif
+
+void dumpregs(struct trapframe*);
+
+static void
+data_abort(struct trapframe *frame, uint64_t esr, int lower, int exe)
+{
+ struct vm_map *map;
+ struct proc *p;
+ struct pcb *pcb;
+ vm_fault_t ftype;
+ vm_prot_t access_type;
+ vaddr_t va;
+ union sigval sv;
+ uint64_t far;
+ int error = 0, sig;
+
+ pcb = curcpu()->ci_curpcb;
+ p = curcpu()->ci_curproc;
+
+ /*
+ * Special case for fuswintr and suswintr. These can't sleep so
+ * handle them early on in the trap handler.
+ */
+ if (__predict_false(pcb->pcb_onfault == (char *)&fsu_intr_fault)) {
+ frame->tf_elr = (register_t)pcb->pcb_onfault;
+ return;
+ }
+
+ far = READ_SPECIALREG(far_el1);
+
+ if (lower)
+ map = &p->p_vmspace->vm_map;
+ else {
+ /* The top bit tells us which range to use */
+ if ((far >> 63) == 1)
+ map = kernel_map;
+ else
+ map = &p->p_vmspace->vm_map;
+ }
+
+ va = trunc_page(far);
+ if (exe)
+ access_type = PROT_READ;
+ else
+ access_type = ((esr >> 6) & 1) ? PROT_WRITE : PROT_READ;
+
+ ftype = VM_FAULT_INVALID; // should check for failed permissions.
+
+ if (map != kernel_map) {
+ /*
+ * Keep swapout from messing with us during this
+ * critical time.
+ */
+ // XXX SMP
+ //PROC_LOCK(p);
+ //++p->p_lock;
+ //PROC_UNLOCK(p);
+
+ /* Fault in the user page: */
+ if (!pmap_fault_fixup(map->pmap, va, access_type, 1)) {
+ error = uvm_fault(map, va, ftype, access_type);
+ }
+
+ //PROC_LOCK(p);
+ //--p->p_lock;
+ //PROC_UNLOCK(p);
+ } else {
+ /*
+ * Don't have to worry about process locking or stacks in the
+ * kernel.
+ */
+ if (!pmap_fault_fixup(map->pmap, va, access_type, 0)) {
+ error = uvm_fault(map, va, ftype, access_type);
+ }
+ }
+
+ if (error != 0) {
+ if (lower) {
+ if (error == ENOMEM)
+ sig = SIGKILL;
+ else
+ sig = SIGSEGV;
+ sv.sival_ptr = (u_int64_t *)far;
+ dumpregs(frame);
+
+ trapsignal(p, sig, 0, SEGV_ACCERR, sv);
+ } else {
+ if (curcpu()->ci_idepth == 0 &&
+ pcb->pcb_onfault != 0) {
+ frame->tf_x[0] = error;
+ frame->tf_elr = (register_t)pcb->pcb_onfault;
+ return;
+ }
+ panic("uvm_fault failed: %lx", frame->tf_elr);
+ }
+ }
+
+ if (lower)
+ userret(p);
+}
+
+void
+do_el1h_sync(struct trapframe *frame)
+{
+ uint32_t exception;
+ uint64_t esr;
+
+ /* Read the esr register to get the exception details */
+ esr = READ_SPECIALREG(esr_el1);
+ exception = ESR_ELx_EXCEPTION(esr);
+
+ /*
+ * Sanity check we are in an exception er can handle. The IL bit
+ * is used to indicate the instruction length, except in a few
+ * exceptions described in the ARMv8 ARM.
+ *
+ * It is unclear in some cases if the bit is implementation defined.
+ * The Foundation Model and QEMU disagree on if the IL bit should
+ * be set when we are in a data fault from the same EL and the ISV
+ * bit (bit 24) is also set.
+ */
+// KASSERT((esr & ESR_ELx_IL) == ESR_ELx_IL ||
+// (exception == EXCP_DATA_ABORT && ((esr & ISS_DATA_ISV) == 0)),
+// ("Invalid instruction length in exception"));
+
+ switch(exception) {
+ case EXCP_FP_SIMD:
+ case EXCP_TRAP_FP:
+ panic("VFP exception in the kernel");
+ case EXCP_DATA_ABORT:
+ data_abort(frame, esr, 0, 0);
+ break;
+ case EXCP_BRK:
+ case EXCP_WATCHPT_EL1:
+ case EXCP_SOFTSTP_EL1:
+#ifdef DDB
+ {
+ /* XXX */
+ int db_trapper (u_int, u_int, trapframe_t *, int);
+ db_trapper(frame->tf_elr, 0/*XXX*/, frame, exception);
+ }
+#else
+ panic("No debugger in kernel.\n");
+#endif
+ break;
+ default:
+#ifdef DDB
+ {
+ /* XXX */
+ int db_trapper (u_int, u_int, trapframe_t *, int);
+ db_trapper(frame->tf_elr, 0/*XXX*/, frame, exception);
+ }
+#endif
+ panic("Unknown kernel exception %x esr_el1 %lx lr %lxpc %lx\n",
+ exception,
+ esr, frame->tf_lr, frame->tf_elr);
+ }
+}
+
+void
+do_el0_sync(struct trapframe *frame)
+{
+ uint32_t exception;
+ uint64_t esr;
+
+ /* Check we have a sane environment when entering from userland */
+// KASSERT((uintptr_t)get_pcpu() >= VM_MIN_KERNEL_ADDRESS,
+// ("Invalid pcpu address from userland: %p (tpidr %lx)",
+// get_pcpu(), READ_SPECIALREG(tpidr_el1)));
+
+ esr = READ_SPECIALREG(esr_el1);
+ exception = ESR_ELx_EXCEPTION(esr);
+
+ switch(exception) {
+ case EXCP_FP_SIMD:
+ case EXCP_TRAP_FP:
+ vfp_fault(frame->tf_elr, 0, frame, exception);
+ break;
+ case EXCP_SVC:
+ vfp_save();
+ svc_handler(frame);
+ break;
+ case EXCP_INSN_ABORT_L:
+ vfp_save();
+ data_abort(frame, esr, 1, 1);
+ break;
+ case EXCP_DATA_ABORT_L:
+ vfp_save();
+ data_abort(frame, esr, 1, 0);
+ break;
+ default:
+ // panic("Unknown userland exception %x esr_el1 %lx\n", exception,
+ // esr);
+ // USERLAND MUST NOT PANIC MACHINE
+ {
+ // only here to debug !?!?
+ void dumpregs(struct trapframe *frame);
+ dumpregs(frame);
+ }
+ sigexit(curproc, SIGILL);
+ userret(curproc);
+ }
+}
+
+void
+do_el0_error(struct trapframe *frame)
+{
+
+ panic("do_el0_error");
+}
+
diff --git a/sys/arch/arm64/arm64/vfp.c b/sys/arch/arm64/arm64/vfp.c
new file mode 100644
index 00000000000..9e3029b97db
--- /dev/null
+++ b/sys/arch/arm64/arm64/vfp.c
@@ -0,0 +1,284 @@
+/* $OpenBSD: vfp.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <arm64/include/vfp.h>
+
+void vfp_store(struct fpreg *vfpsave);
+
+static inline void set_vfp_enable(int val)
+{
+ uint64_t v;
+ __asm __volatile("mrs %x0, cpacr_el1" : "=r" (v));
+ if (val != 0) {
+ v |= VFP_UFPEN;
+ } else {
+ v &= ~(VFP_UFPEN);
+ }
+ __asm __volatile("msr cpacr_el1, %x0" :: "r" (v));
+}
+
+static inline int get_vfp_enable()
+{
+ uint64_t v;
+ int enabled = 0;
+ __asm __volatile("mrs %x0, cpacr_el1" : "=r" (v));
+ if ((v & VFP_UFPEN) == VFP_UFPEN )
+ enabled = 1;
+ return enabled;
+}
+
+int
+vfp_fault(vaddr_t pc, uint32_t insn, trapframe_t *tf, int fault_code);
+void vfp_load(struct proc *p);
+
+void
+vfp_init(void)
+{
+ static int inited = 0;
+
+ if (inited == 1)
+ return;
+ inited = 1;
+
+ /* Read Coprocessor Access Control Register */
+
+ /* other stuff?? */
+}
+
+void
+vfp_store(struct fpreg *vfpsave)
+{
+ uint32_t scratch;
+
+ if (get_vfp_enable()) {
+ __asm __volatile(
+ "str q0, [%x1]\n"
+ "str q1, [%x1, #0x10]\n"
+ "str q2, [%x1, #0x20]\n"
+ "str q3, [%x1, #0x30]\n"
+ "str q4, [%x1, #0x40]\n"
+ "str q5, [%x1, #0x50]\n"
+ "str q6, [%x1, 0x60]\n"
+ "str q7, [%x1, #0x70]\n"
+ "str q8, [%x1, #0x80]\n"
+ "str q9, [%x1, #0x90]\n"
+ "str q10, [%x1, #0xa0]\n"
+ "str q11, [%x1, #0xb0]\n"
+ "str q12, [%x1, #0xc0]\n"
+ "str q13, [%x1, 0xd0]\n"
+ "str q14, [%x1, #0xe0]\n"
+ "str q15, [%x1, #0xf0]\n"
+ "str q16, [%x1, #0x100]\n"
+ "str q17, [%x1, #0x110]\n"
+ "str q18, [%x1, #0x120]\n"
+ "str q19, [%x1, #0x130]\n"
+ "str q20, [%x1, #0x140]\n"
+ "str q21, [%x1, #0x150]\n"
+ "str q22, [%x1, #0x160]\n"
+ "str q23, [%x1, #0x170]\n"
+ "str q24, [%x1, #0x180]\n"
+ "str q25, [%x1, #0x190]\n"
+ "str q26, [%x1, #0x1a0]\n"
+ "str q27, [%x1, #0x1b0]\n"
+ "str q28, [%x1, #0x1c0]\n"
+ "str q29, [%x1, #0x1d0]\n"
+ "str q30, [%x1, #0x1e0]\n"
+ "str q31, [%x1, #0x1f0]\n"
+ "mrs %x0, fpsr\n"
+ "str %w0, [%x1, 0x200]\n" /* save vfpscr */
+ "mrs %x0, fpcr\n"
+ "str %w0, [%x1, 0x204]\n" /* save vfpscr */
+ : "=&r" (scratch) : "r" (vfpsave));
+ }
+
+ /* disable FPU */
+ set_vfp_enable(0);
+}
+
+void
+vfp_save(void)
+{
+ struct cpu_info *ci = curcpu();
+ struct pcb *pcb;
+ struct proc *p;
+
+ uint32_t vfp_enabled;
+
+ if (ci->ci_fpuproc == 0)
+ return;
+
+ vfp_enabled = get_vfp_enable();
+
+ if (!vfp_enabled)
+ return; /* not enabled, nothing to do */
+
+#if 0
+ // arm32 had failures flags, verify this on aarch64
+ if (vfp_enabled)
+ panic("vfp exceptional data fault, time to write more code");
+#endif
+
+ p = curproc;
+ pcb = curpcb;
+
+ if (pcb->pcb_fpcpu == NULL || ci->ci_fpuproc == NULL ||
+ !(pcb->pcb_fpcpu == ci && ci->ci_fpuproc == p)) {
+ /* disable fpu before panic, otherwise recurse */
+ set_vfp_enable(0);
+
+ panic("FPU unit enabled when curproc and curcpu dont agree %p %p %p %p", pcb->pcb_fpcpu, ci, ci->ci_fpuproc, p);
+ }
+
+ vfp_store(&p->p_addr->u_pcb.pcb_fpstate);
+
+ /* NOTE: fpu state is saved but remains 'valid', as long as
+ * curpcb()->pcb_fpucpu == ci && ci->ci_fpuproc == curproc()
+ * is true FPU state is valid and can just be enabled without reload.
+ */
+ set_vfp_enable(0);
+}
+
+void
+vfp_enable()
+{
+ struct cpu_info *ci = curcpu();
+
+ if (curproc->p_addr->u_pcb.pcb_fpcpu == ci &&
+ ci->ci_fpuproc == curproc) {
+ disable_interrupts();
+
+ /* FPU state is still valid, just enable and go */
+ set_vfp_enable(1);
+ }
+}
+
+void
+vfp_load(struct proc *p)
+{
+ struct cpu_info *ci = curcpu();
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ uint32_t scratch = 0;
+ int psw;
+
+ /* do not allow a partially synced state here */
+ psw = disable_interrupts();
+
+ /*
+ * p->p_pcb->pcb_fpucpu _may_ not be NULL here, but the FPU state
+ * was synced on kernel entry, so we can steal the FPU state
+ * instead of signalling and waiting for it to save
+ */
+
+ /* enable to be able to load ctx */
+ set_vfp_enable(1);
+
+ __asm __volatile(
+ "ldr q0, [%x1]\n"
+ "ldr q1, [%x1, #0x10]\n"
+ "ldr q2, [%x1, #0x20]\n"
+ "ldr q3, [%x1, #0x30]\n"
+ "ldr q4, [%x1, #0x40]\n"
+ "ldr q5, [%x1, #0x50]\n"
+ "ldr q6, [%x1, 0x60]\n"
+ "ldr q7, [%x1, #0x70]\n"
+ "ldr q8, [%x1, #0x80]\n"
+ "ldr q9, [%x1, #0x90]\n"
+ "ldr q10, [%x1, #0xa0]\n"
+ "ldr q11, [%x1, #0xb0]\n"
+ "ldr q12, [%x1, #0xc0]\n"
+ "ldr q13, [%x1, 0xd0]\n"
+ "ldr q14, [%x1, #0xe0]\n"
+ "ldr q15, [%x1, #0xf0]\n"
+ "ldr q16, [%x1, #0x100]\n"
+ "ldr q17, [%x1, #0x110]\n"
+ "ldr q18, [%x1, #0x120]\n"
+ "ldr q19, [%x1, #0x130]\n"
+ "ldr q20, [%x1, #0x140]\n"
+ "ldr q21, [%x1, #0x150]\n"
+ "ldr q22, [%x1, #0x160]\n"
+ "ldr q23, [%x1, #0x170]\n"
+ "ldr q24, [%x1, #0x180]\n"
+ "ldr q25, [%x1, #0x190]\n"
+ "ldr q26, [%x1, #0x1a0]\n"
+ "ldr q27, [%x1, #0x1b0]\n"
+ "ldr q28, [%x1, #0x1c0]\n"
+ "ldr q29, [%x1, #0x1d0]\n"
+ "ldr q30, [%x1, #0x1e0]\n"
+ "ldr q31, [%x1, #0x1f0]\n"
+
+ "ldr %w0, [%x1, #0x200]\n" /* set old fpsr */
+ "msr fpsr, %x0\n"
+ "ldr %w0, [%x1, #0x204]\n" /* set old fpsr */
+ "msr fpcr, %x0\n"
+ : "=&r" (scratch) : "r" (&pcb->pcb_fpstate));
+
+ ci->ci_fpuproc = p;
+ pcb->pcb_fpcpu = ci;
+
+ /* disable until return to userland */
+ set_vfp_enable(0);
+
+ restore_interrupts(psw);
+}
+
+
+int
+vfp_fault(vaddr_t pc, uint32_t insn, trapframe_t *tf, int fault_code)
+{
+ struct proc *p;
+ struct pcb *pcb;
+ struct cpu_info *ci;
+
+ p = curproc;
+ pcb = &p->p_addr->u_pcb;
+ ci = curcpu();
+
+ if (get_vfp_enable()) {
+ /*
+ * We probably ran into an unsupported instruction,
+ * like NEON on a non-NEON system. Let the process know.
+ */
+ return 1;
+ }
+
+ /* we should be able to ignore old state of pcb_fpcpu ci_fpuproc */
+ if ((pcb->pcb_flags & PCB_FPU) == 0) {
+ pcb->pcb_flags |= PCB_FPU;
+
+ bzero (&pcb->pcb_fpstate, sizeof (pcb->pcb_fpstate));
+
+ /* XXX - setround()? */
+ }
+ vfp_load(p);
+
+ return 0;
+}
+
+void
+vfp_discard(struct proc *p)
+{
+ struct cpu_info *ci = curcpu();
+ if (curpcb->pcb_fpcpu == ci && ci->ci_fpuproc == p) {
+ ci->ci_fpuproc = NULL;
+ curpcb->pcb_fpcpu = NULL;
+ }
+}
diff --git a/sys/arch/arm64/arm64/vm_machdep.c b/sys/arch/arm64/arm64/vm_machdep.c
new file mode 100644
index 00000000000..c2e42e53234
--- /dev/null
+++ b/sys/arch/arm64/arm64/vm_machdep.c
@@ -0,0 +1,183 @@
+/* $OpenBSD: vm_machdep.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.1 2003/04/26 18:39:33 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * Copyright (c) 1989, 1990 William Jolitz
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and William Jolitz.
+ *
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
+ */
+
+/*
+ * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/buf.h>
+#include <sys/user.h>
+#include <sys/exec.h>
+#include <sys/ptrace.h>
+#include <sys/signalvar.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/reg.h>
+#include <machine/vfp.h>
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent. Returns 1 in the child process, 0 in the parent.
+ */
+void
+cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
+ void (*func)(void *), void *arg)
+{
+ struct pcb *pcb = (struct pcb *)&p2->p_addr->u_pcb;
+ struct trapframe *tf;
+ struct switchframe *sf;
+
+ // Does any flushing need to be done if process was running?
+
+ // Copy the pcb.
+ *pcb = p1->p_addr->u_pcb;
+
+ pmap_activate(p2);
+
+ tf = (struct trapframe *)((u_long)p2->p_addr
+ + USPACE
+ - sizeof(struct trapframe)
+ - 0x10);
+
+ tf = (struct trapframe *)STACKALIGN(tf);
+ p2->p_addr->u_pcb.pcb_tf = tf;
+ *tf = *p1->p_addr->u_pcb.pcb_tf;
+
+ if (stack != NULL)
+ tf->tf_sp = STACKALIGN((u_int)(stack) + stacksize);
+
+ sf = (struct switchframe *)tf - 1;
+ sf->sf_x19 = (uint64_t)func;
+ sf->sf_x20= (uint64_t)arg;
+ sf->sf_lr = (u_int64_t)&proc_trampoline;
+ pcb->pcb_sp = (uint64_t)sf;
+}
+
+/*
+ * cpu_exit is called as the last action during exit.
+ *
+ * We clean up a little and then call sched_exit() with the old proc as an
+ * argument.
+ */
+void
+cpu_exit(struct proc *p)
+{
+ /* If we were using the FPU, forget about it. */
+ if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
+ vfp_discard(p);
+
+ pmap_deactivate(p);
+ sched_exit(p);
+}
+
+struct kmem_va_mode kv_physwait = {
+ .kv_map = &phys_map,
+ .kv_wait = 1,
+};
+
+/*
+ * Map a user I/O request into kernel virtual address space.
+ * Note: the pages are already locked by uvm_vslock(), so we
+ * do not need to pass an access_type to pmap_enter().
+ */
+void
+vmapbuf(struct buf *bp, vsize_t len)
+{
+ vaddr_t faddr, taddr, off;
+ paddr_t fpa;
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vmapbuf");
+ faddr = trunc_page((vaddr_t)(bp->b_saveaddr = bp->b_data));
+ off = (vaddr_t)bp->b_data - faddr;
+ len = round_page(off + len);
+ taddr = (vaddr_t)km_alloc(len, &kv_physwait, &kp_none, &kd_waitok);
+ bp->b_data = (caddr_t)(taddr + off);
+ /*
+ * The region is locked, so we expect that pmap_pte() will return
+ * non-NULL.
+ * XXX: unwise to expect this in a multithreaded environment.
+ * anything can happen to a pmap between the time we lock a
+ * region, release the pmap lock, and then relock it for
+ * the pmap_extract().
+ *
+ * no need to flush TLB since we expect nothing to be mapped
+ * where we we just allocated (TLB will be flushed when our
+ * mapping is removed).
+ */
+ while (len) {
+ (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map),
+ faddr, &fpa);
+ pmap_kenter_pa(taddr, fpa, PROT_READ | PROT_WRITE);
+ faddr += PAGE_SIZE;
+ taddr += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+}
+
+/*
+ * Unmap a previously-mapped user I/O request.
+ */
+void
+vunmapbuf(struct buf *bp, vsize_t len)
+{
+ vaddr_t addr, off;
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+ addr = trunc_page((vaddr_t)bp->b_data);
+ off = (vaddr_t)bp->b_data - addr;
+ len = round_page(off + len);
+ pmap_kremove(addr, len);
+ pmap_update(pmap_kernel());
+ km_free((void *)addr, len, &kv_physwait, &kp_none);
+ bp->b_data = bp->b_saveaddr;
+ bp->b_saveaddr = 0;
+}
diff --git a/sys/arch/arm64/compile/GENERIC/Makefile b/sys/arch/arm64/compile/GENERIC/Makefile
new file mode 100644
index 00000000000..01b5f23410c
--- /dev/null
+++ b/sys/arch/arm64/compile/GENERIC/Makefile
@@ -0,0 +1 @@
+.include "../Makefile.inc"
diff --git a/sys/arch/arm64/compile/Makefile b/sys/arch/arm64/compile/Makefile
new file mode 100644
index 00000000000..37e48f8f5de
--- /dev/null
+++ b/sys/arch/arm64/compile/Makefile
@@ -0,0 +1,7 @@
+# $OpenBSD: Makefile,v 1.1 2016/12/17 23:38:33 patrick Exp $
+
+.if make(obj) || make(clean) || make(cleandir)
+SUBDIR!=find . -type d -maxdepth 1 \! \( -name . -o -name CVS \) | cut -b3-
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/sys/arch/arm64/compile/Makefile.inc b/sys/arch/arm64/compile/Makefile.inc
new file mode 100644
index 00000000000..d9c886d0740
--- /dev/null
+++ b/sys/arch/arm64/compile/Makefile.inc
@@ -0,0 +1,18 @@
+SYSDIR != cd ${.CURDIR}/../../../..; pwd
+CONFDIR != cd ${.CURDIR}/../../conf; pwd
+
+.if ${.CURDIR} == ${.OBJDIR}
+.PHONY: config
+config:
+ @echo make obj required first >&2
+ @false
+.else
+.PHONY: config clean
+config:
+ config -b ${.OBJDIR} -s ${SYSDIR} ${CONFDIR}/${.CURDIR:T}
+.endif
+
+cleandir clean:
+
+.include <bsd.obj.mk>
+
diff --git a/sys/arch/arm64/compile/RAMDISK/Makefile b/sys/arch/arm64/compile/RAMDISK/Makefile
new file mode 100644
index 00000000000..01b5f23410c
--- /dev/null
+++ b/sys/arch/arm64/compile/RAMDISK/Makefile
@@ -0,0 +1 @@
+.include "../Makefile.inc"
diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC
new file mode 100644
index 00000000000..fcef53dfbfc
--- /dev/null
+++ b/sys/arch/arm64/conf/GENERIC
@@ -0,0 +1,58 @@
+# $OpenBSD: GENERIC,v 1.1 2016/12/17 23:38:33 patrick Exp $
+#
+# GENERIC machine description file
+#
+# This machine description file is used to generate the default OpenBSD
+# kernel. The generic kernel does not include all options, subsystems
+# and device drivers, but should be useful for most applications.
+#
+# The machine description file can be customised for your specific
+# machine to reduce the kernel size and improve its performance.
+#
+# For further information on compiling OpenBSD kernels, see the config(8)
+# man page.
+#
+# For further information on hardware support for this architecture, see
+# the intro(4) man page. For further information about kernel options
+# for this architecture, see the options(4) man page. For an explanation
+# of each device driver in this file see the section 4 man page for the
+# device.
+
+machine arm64
+include "../../../conf/GENERIC"
+maxusers 32
+
+options TIMEZONE=0 # time zone to adjust RTC time by
+options DST=0 # daylight saving time used by RTC
+#options NFSCLIENT # NFS
+options SYSCALL_DEBUG
+
+makeoptions KERNEL_BASE_PHYS="0x00200000"
+makeoptions KERNEL_BASE_VIRT="0xffffff8000200000"
+
+config bsd swap generic
+
+# The main bus device
+mainbus0 at root
+simplebus* at fdt?
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+ch* at scsibus?
+uk* at scsibus?
+
+ampintc* at fdt?
+agtimer* at fdt?
+
+# NS16550 compatible serial ports
+com* at fdt?
+
+# Virt on-chip devices
+pluart* at fdt? # onboard uarts
+virtio* at fdt?
+vio* at virtio?
+vioblk* at virtio?
+viomb* at virtio?
+viornd* at virtio?
diff --git a/sys/arch/arm64/conf/Makefile.arm64 b/sys/arch/arm64/conf/Makefile.arm64
new file mode 100644
index 00000000000..75b57c9784b
--- /dev/null
+++ b/sys/arch/arm64/conf/Makefile.arm64
@@ -0,0 +1,196 @@
+# $OpenBSD: Makefile.arm64,v 1.1 2016/12/17 23:38:33 patrick Exp $
+
+# For instructions on building kernels consult the config(8) and options(4)
+# manual pages.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+# DEBUG is set to -g by config if debugging is requested (config -g).
+# PROF is set to -pg by config if profiling is requested (config -p).
+
+.include <bsd.own.mk>
+
+SIZE?= size
+STRIP?= strip
+
+# source tree is located via $S relative to the compilation directory
+.ifndef S
+S!= cd ../../../..; pwd
+.endif
+
+_machdir?= $S/arch/${_mach}
+_archdir?= $S/arch/${_arch}
+
+INCLUDES= -nostdinc -I$S -I. -I$S/arch
+CPPFLAGS= ${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -D__${_mach}__ -MD -MP
+#CWARNFLAGS= -Werror -Wall -Wstrict-prototypes -Wmissing-prototypes \
+CWARNFLAGS= -Werror -Wall -Wstrict-prototypes \
+ -Wno-main -Wno-uninitialized -Wno-format -Wno-pointer-sign \
+ -Wno-conditional-uninitialized
+# -Wstack-larger-than-2047
+
+CMACHFLAGS= -ffreestanding -mcpu=cortex-a57+nofp+nosimd \
+ -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer \
+ -ffixed-x18
+#CMACHFLAGS+= -fno-builtin-printf -fno-builtin-snprintf \
+# -fno-builtin-vsnprintf -fno-builtin-log \
+# -fno-builtin-log2 -fno-builtin-malloc ${NOPIE_FLAGS}
+.if ${IDENT:M-DNO_PROPOLICE}
+CMACHFLAGS+= -fno-stack-protector
+.endif
+
+COPTS?= -O2
+CFLAGS= ${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE}
+AFLAGS= -D_LOCORE -x assembler-with-cpp ${CWARNFLAGS} ${CMACHFLAGS}
+LINKFLAGS= -T ldscript --warn-common -nopie
+
+.if ${IDENT:M-DDDB_STRUCT}
+DB_STRUCTINFO= db_structinfo.h
+.else
+DB_STRUCTINFO=
+.endif
+
+HOSTCC?= ${CC}
+HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
+HOSTED_CFLAGS= ${CFLAGS}
+HOSTED_C= ${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $<
+
+NORMAL_C_NOP= ${CC} ${CFLAGS} ${CPPFLAGS} -c $<
+NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
+NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $<
+
+%OBJS
+
+%CFILES
+
+%SFILES
+
+# load lines for config "xxx" will be emitted as:
+# xxx: ${SYSTEM_DEP} swapxxx.o
+# ${SYSTEM_LD_HEAD}
+# ${SYSTEM_LD} swapxxx.o
+# ${SYSTEM_LD_TAIL}
+SYSTEM_HEAD= locore.o param.o ioconf.o
+SYSTEM_OBJ= ${SYSTEM_HEAD} ${OBJS}
+SYSTEM_DEP= Makefile ${SYSTEM_OBJ}
+SYSTEM_LD_HEAD= @rm -f $@
+SYSTEM_LD_HEAD+=; \
+ cat ${_archdir}/conf/kern.ldscript | \
+ sed -e 's/@KERNEL_BASE_PHYS@/${KERNEL_BASE_PHYS}/' \
+ -e 's/@KERNEL_BASE_VIRT@/${KERNEL_BASE_VIRT}/' > ldscript
+
+SYSTEM_LD= @echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_HEAD} vers.o $${OBJS}'; \
+ ${LD} ${LINKFLAGS} -o $@ ${SYSTEM_HEAD} vers.o ${OBJS}
+SYSTEM_LD_TAIL= @${SIZE} $@; chmod 755 $@
+
+DEBUG?=
+.if ${DEBUG} == "-g"
+LINKFLAGS+= -X
+STRIPFLAGS= -g -x
+SYSTEM_LD_TAIL+=; \
+ echo mv $@ $@.gdb; rm -f $@.gdb; mv $@ $@.gdb; \
+ echo ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb; \
+ ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb
+.else
+LINKFLAGS+= -x
+.endif
+
+%LOAD
+
+# cc's -MD puts the source and output paths in the dependency file;
+# since those are temp files here we need to fix it up. It also
+# puts the file in /tmp, so we use -MF to put it in the current
+# directory as assym.P and then generate assym.d from it with a
+# good target name
+assym.h: $S/kern/genassym.sh Makefile \
+ ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf
+ cat ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf | \
+ sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} -no-integrated-as -MF assym.P > assym.h.tmp
+ sed '1s/.*/assym.h: \\/' assym.P > assym.d
+ sort -u assym.h.tmp > assym.h
+
+param.c: $S/conf/param.c
+ rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${NORMAL_C}
+
+mcount.o: $S/lib/libkern/mcount.c Makefile
+ ${NORMAL_C_NOP}
+
+ioconf.o: ioconf.c
+ ${NORMAL_C}
+
+vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
+ sh $S/conf/newvers.sh
+ ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c
+
+clean::
+ rm -f eddep *bsd *bsd.gdb tags *.[dio] [a-z]*.s \
+ [Ee]rrs linterrs assym.h ${DB_STRUCTINFO}
+
+lint:
+ @lint -hbxncez -Dvolatile= ${CPPFLAGS} -UKGDB \
+ ${CFILES} ioconf.c param.c | \
+ grep -v 'static function .* unused'
+
+depend:
+ @touch $@
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+db_structinfo.h: $S/ddb/db_structinfo.c $S/ddb/parse_structinfo.pl
+ ${CC} ${CFLAGS} ${CPPFLAGS} -MT $@ -gstabs -c $S/ddb/db_structinfo.c
+ objdump -g db_structinfo.o | perl $S/ddb/parse_structinfo.pl > $@
+ rm -f db_structinfo.o
+
+locore.o: ${_archdir}/${_arch}/locore.S assym.h
+in_cksum_arm.o fiq_subr.o bcopyinout.o copystr.o sigcode.o copy.o: assym.h
+vectors.o cpuswitch.o exception.o bcopy_page.o irq_dispatch.o support.o: assym.h
+
+# The install target can be redefined by putting a
+# install-kernel-${MACHINE_NAME} target into /etc/mk.conf
+MACHINE_NAME!= uname -n
+install: install-kernel-${MACHINE_NAME}
+.if !target(install-kernel-${MACHINE_NAME}})
+install-kernel-${MACHINE_NAME}:
+ rm -f /obsd
+ ln /bsd /obsd
+ cp bsd /nbsd
+ mv /nbsd /bsd
+.endif
+
+# pull in the dependency information
+.if !empty(DB_STRUCTINFO) && !exists(${DB_STRUCTINFO})
+ ${SYSTEM_OBJ}: ${DB_STRUCTINFO}
+.endif
+.ifnmake clean
+. for o in ${SYSTEM_OBJ} assym.h ${DB_STRUCTINFO}
+. if exists(${o:R}.d)
+. include "${o:R}.d"
+. elif exists($o)
+ .PHONY: $o
+. endif
+. endfor
+.endif
+
+
+## for qemu this is where ram is located
+RAM_ADDR?=0x40000000
+#KERNEL_LOAD_ADDR!=echo "x = hex(${KERNEL_BASE_PHYS} + ${RAM_ADDR}); print x" | python
+KERNEL_LOAD_ADDR=0x40200000
+
+# until we get native booting working, put this in the tree.
+bsdrd.umg: bsd.rd
+ mkuboot -a arm -o linux -e ${KERNEL_LOAD_ADDR} -l ${KERNEL_LOAD_ADDR} bsd.rd bsdrd.umg
+
+bsd.umg: bsd
+ mkuboot -a arm -o linux -e ${KERNEL_LOAD_ADDR} -l ${KERNEL_LOAD_ADDR} bsd bsd.umg
+
+bsd.rd: bsd
+ cp bsd bsd.rd
+ rdconfig bsd.rd $S/../distrib/${_mach}/ramdisk/mr.fs
+
+%RULES
diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64
new file mode 100644
index 00000000000..d03b7640744
--- /dev/null
+++ b/sys/arch/arm64/conf/files.arm64
@@ -0,0 +1,106 @@
+# $OpenBSD: files.arm64,v 1.1 2016/12/17 23:38:33 patrick Exp $
+
+maxpartitions 16
+maxusers 2 8 64
+
+major {wd = 16}
+major {sd = 24}
+major {cd = 26}
+
+file arch/arm64/arm64/autoconf.c
+file arch/arm64/arm64/copy.S
+file arch/arm64/arm64/copystr.S
+file arch/arm64/arm64/cpuswitch.S
+file arch/arm64/arm64/conf.c
+file arch/arm64/arm64/disksubr.c
+file arch/arm64/arm64/machdep.c
+file arch/arm64/arm64/mem.c
+file arch/arm64/arm64/pmap.c
+file arch/arm64/arm64/vm_machdep.c
+file arch/arm64/arm64/process_machdep.c
+file arch/arm64/arm64/sig_machdep.c
+file arch/arm64/arm64/syscall.c
+file arch/arm64/arm64/sys_machdep.c
+
+file arch/arm64/arm64/intr.c
+file arch/arm64/arm64/softintr.c
+file arch/arm64/arm64/vfp.c
+file arch/arm64/arm64/exception.S
+file arch/arm64/arm64/trap.c
+file arch/arm64/arm64/ast.c
+file arch/arm64/arm64/arm64_mutex.c
+
+
+file arch/arm64/arm64/support.S
+file arch/arm64/arm64/bus_dma.c
+file arch/arm64/arm64/arm64_iobus.c
+
+file arch/arm64/dev/arm64_bus_space.c
+
+file arch/arm64/arm64/db_disasm.c ddb
+file arch/arm64/arm64/db_interface.c ddb
+file arch/arm64/arm64/db_trace.c ddb
+
+define fdt {[early = 0]}
+
+# mainbus files
+device mainbus: fdt
+attach mainbus at root
+file arch/arm64/dev/mainbus.c mainbus
+
+device simplebus: fdt
+attach simplebus at fdt
+file arch/arm64/dev/simplebus.c simplebus
+
+# FDT support
+file dev/ofw/fdt.c
+file dev/ofw/ofw_clock.c
+file dev/ofw/ofw_gpio.c
+file dev/ofw/ofw_pinctrl.c
+file dev/ofw/ofw_regulator.c
+
+# Machine-independent SCSI drivers
+include "scsi/files.scsi"
+include "dev/atapiscsi/files.atapiscsi"
+
+# Machine-independent ATA drivers
+include "dev/ata/files.ata"
+
+# Include WSCONS stuff
+include "dev/wscons/files.wscons"
+include "dev/rasops/files.rasops"
+include "dev/wsfont/files.wsfont"
+
+#
+# Machine-independent HID support
+#
+include "dev/hid/files.hid"
+
+# Include USB stuff
+include "dev/usb/files.usb"
+
+file netinet/in_cksum.c
+file netinet/in4_cksum.c
+
+include "dev/mii/files.mii"
+include "dev/pci/files.pci"
+
+# Console related stuff
+attach com at fdt with com_fdt
+file arch/arm64/dev/com_fdt.c com_fdt
+
+# ARM PrimeCell PL011 UART
+device pluart
+attach pluart at fdt
+file arch/arm64/dev/pluart.c pluart
+
+device ampintc
+attach ampintc at fdt
+file arch/arm64/dev/ampintc.c ampintc
+
+device agtimer
+attach agtimer at fdt
+file arch/arm64/dev/agtimer.c agtimer
+
+attach virtio at fdt with virtio_mmio
+file arch/arm64/dev/virtio_mmio.c virtio_mmio
diff --git a/sys/arch/arm64/conf/kern.ldscript b/sys/arch/arm64/conf/kern.ldscript
new file mode 100644
index 00000000000..7408420e44c
--- /dev/null
+++ b/sys/arch/arm64/conf/kern.ldscript
@@ -0,0 +1,81 @@
+/* $OpenBSD: kern.ldscript,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $OpenBSD: kern.ldscript,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: ldscript.evbarm,v 1.2 2003/03/05 23:54:22 thorpej Exp $ */
+
+OUTPUT_ARCH(aarch64)
+
+/* Define how we want our ELF binary to look like. */
+PHDRS
+{
+ text PT_LOAD;
+ rodata PT_LOAD;
+ data PT_LOAD;
+ openbsd_randomize PT_OPENBSD_RANDOMIZE;
+}
+
+__ALIGN_SIZE = 0x1000;
+__kernel_base = @KERNEL_BASE_VIRT@;
+
+ENTRY(_start)
+SECTIONS
+{
+ . = __kernel_base;
+ .text :
+ {
+ *(.text .text.*)
+ *(.stub)
+ *(.glue_7t) *(.glue_7)
+ } :text =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ /* Move rodata to the next page, so we can nuke X and W bit on it */
+ . = ALIGN(__ALIGN_SIZE);
+ .rodata :
+ {
+ *(.rodata .rodata.*)
+ } :rodata
+ PROVIDE (erodata = .);
+ _erodata = .;
+
+ /* Move .random to the next page, so we can add W bit on it and .data */
+ . = ALIGN(__ALIGN_SIZE);
+ .openbsd.randomdata :
+ {
+ *(.openbsd.randomdata)
+ } :openbsd_randomize :data
+ .data :
+ {
+ *(.data .data.*)
+ } :data
+ .sdata :
+ {
+ *(.sdata .sdata.*)
+ } :data
+ PROVIDE (edata = .);
+ _edata = .;
+
+ PROVIDE (__bss_start = .);
+ .sbss :
+ {
+ *(.dynsbss)
+ *(.sbss)
+ *(.sbss.*)
+ *(.scommon)
+ } :data
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+ } :data
+ . = ALIGN(32 / 8);
+ _end = .;
+ PROVIDE (end = .);
+}
diff --git a/sys/arch/arm64/dev/agtimer.c b/sys/arch/arm64/dev/agtimer.c
new file mode 100644
index 00000000000..98e96c0cc9e
--- /dev/null
+++ b/sys/arch/arm64/dev/agtimer.c
@@ -0,0 +1,392 @@
+/* $OpenBSD: agtimer.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2013 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/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/timetc.h>
+#include <sys/evcount.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
+/* registers */
+#define GTIMER_CNTP_CTL_ENABLE (1 << 0)
+#define GTIMER_CNTP_CTL_IMASK (1 << 1)
+#define GTIMER_CNTP_CTL_ISTATUS (1 << 2)
+
+#define TIMER_FREQUENCY 24 * 1000 * 1000 /* ARM core clock */
+int32_t agtimer_frequency = TIMER_FREQUENCY;
+
+u_int agtimer_get_timecount(struct timecounter *);
+
+static struct timecounter agtimer_timecounter = {
+ agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
+};
+
+#define MAX_ARM_CPUS 8
+
+struct agtimer_pcpu_softc {
+ uint64_t pc_nexttickevent;
+ uint64_t pc_nextstatevent;
+ u_int32_t pc_ticks_err_sum;
+};
+
+struct agtimer_softc {
+ struct device sc_dev;
+ int sc_node;
+
+ struct agtimer_pcpu_softc sc_pstat[MAX_ARM_CPUS];
+
+ u_int32_t sc_ticks_err_cnt;
+ u_int32_t sc_ticks_per_second;
+ u_int32_t sc_ticks_per_intr;
+ u_int32_t sc_statvar;
+ u_int32_t sc_statmin;
+
+#ifdef AMPTIMER_DEBUG
+ struct evcount sc_clk_count;
+ struct evcount sc_stat_count;
+#endif
+};
+
+int agtimer_match(struct device *, void *, void *);
+void agtimer_attach(struct device *, struct device *, void *);
+uint64_t agtimer_readcnt64(void);
+int agtimer_intr(void *);
+void agtimer_cpu_initclocks(void);
+void agtimer_delay(u_int);
+void agtimer_setstatclockrate(int stathz);
+void agtimer_set_clockrate(int32_t new_frequency);
+void agtimer_startclock(void);
+
+struct cfattach agtimer_ca = {
+ sizeof (struct agtimer_softc), agtimer_match, agtimer_attach
+};
+
+struct cfdriver agtimer_cd = {
+ NULL, "agtimer", DV_DULL
+};
+
+uint64_t
+agtimer_readcnt64(void)
+{
+ uint64_t val;
+
+ __asm volatile("MRS %x0, CNTPCT_EL0" : "=r" (val));
+
+ return (val);
+}
+
+static inline int
+agtimer_get_ctrl(void)
+{
+ uint32_t val;
+
+ __asm volatile("MRS %x0, CNTP_CTL_EL0" : "=r" (val));
+
+ return (val);
+}
+
+static inline int
+agtimer_set_ctrl(uint32_t val)
+{
+ __asm volatile("MSR CNTP_CTL_EL0, %x0" : "=r" (val));
+
+ //cpu_drain_writebuf();
+ //isb();
+
+ return (0);
+}
+
+static inline int
+agtimer_set_tval(uint32_t val)
+{
+ __asm volatile("MSR CNTP_TVAL_EL0, %x0" : : [val] "r" (val));
+
+ //cpu_drain_writebuf();
+ //isb();
+
+ return (0);
+}
+
+int
+agtimer_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *faa = (struct fdt_attach_args *)aux;
+
+ return OF_is_compatible(faa->fa_node, "arm,armv8-timer");
+}
+
+void
+agtimer_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct agtimer_softc *sc = (struct agtimer_softc *)self;
+ struct fdt_attach_args *faa = aux;
+
+ sc->sc_node = faa->fa_node;
+
+ agtimer_frequency =
+ OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency);
+ sc->sc_ticks_per_second = agtimer_frequency;
+
+ printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000);
+
+ /* XXX: disable user access */
+
+#ifdef AMPTIMER_DEBUG
+ evcount_attach(&sc->sc_clk_count, "clock", NULL);
+ evcount_attach(&sc->sc_stat_count, "stat", NULL);
+#endif
+
+ /*
+ * private timer and interrupts not enabled until
+ * timer configures
+ */
+
+ arm_clock_register(agtimer_cpu_initclocks, agtimer_delay,
+ agtimer_setstatclockrate, agtimer_startclock);
+
+ agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
+ agtimer_timecounter.tc_priv = sc;
+
+ tc_init(&agtimer_timecounter);
+}
+
+u_int
+agtimer_get_timecount(struct timecounter *tc)
+{
+ return agtimer_readcnt64();
+}
+
+int
+agtimer_intr(void *frame)
+{
+ struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
+ struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
+ uint64_t now;
+ uint64_t nextevent;
+ uint32_t r;
+#if defined(USE_GTIMER_CMP)
+ int skip = 1;
+#else
+ int64_t delay;
+#endif
+ int rc = 0;
+
+ /*
+ * DSR - I know that the tick timer is 64 bits, but the following
+ * code deals with rollover, so there is no point in dealing
+ * with the 64 bit math, just let the 32 bit rollover
+ * do the right thing
+ */
+
+ now = agtimer_readcnt64();
+
+ while (pc->pc_nexttickevent <= now) {
+ pc->pc_nexttickevent += sc->sc_ticks_per_intr;
+ pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt;
+
+ /* looping a few times is faster than divide */
+ while (pc->pc_ticks_err_sum > hz) {
+ pc->pc_nexttickevent += 1;
+ pc->pc_ticks_err_sum -= hz;
+ }
+
+#ifdef AMPTIMER_DEBUG
+ sc->sc_clk_count.ec_count++;
+#endif
+ rc = 1;
+ hardclock(frame);
+ }
+ while (pc->pc_nextstatevent <= now) {
+ do {
+ r = random() & (sc->sc_statvar -1);
+ } while (r == 0); /* random == 0 not allowed */
+ pc->pc_nextstatevent += sc->sc_statmin + r;
+
+ /* XXX - correct nextstatevent? */
+#ifdef AMPTIMER_DEBUG
+ sc->sc_stat_count.ec_count++;
+#endif
+ rc = 1;
+ statclock(frame);
+ }
+
+ if (pc->pc_nexttickevent < pc->pc_nextstatevent)
+ nextevent = pc->pc_nexttickevent;
+ else
+ nextevent = pc->pc_nextstatevent;
+
+ delay = nextevent - now;
+ if (delay < 0)
+ delay = 1;
+
+ agtimer_set_tval(delay);
+
+ return (rc);
+}
+
+void
+agtimer_set_clockrate(int32_t new_frequency)
+{
+ struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
+
+ agtimer_frequency = new_frequency;
+
+ if (sc == NULL)
+ return;
+
+ sc->sc_ticks_per_second = agtimer_frequency;
+ agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
+ printf("agtimer0: adjusting clock: new tick rate %d KHz\n",
+ sc->sc_ticks_per_second /1000);
+}
+
+void
+agtimer_cpu_initclocks()
+{
+ struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
+ struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
+ uint32_t reg;
+ uint64_t next;
+
+ stathz = hz;
+ profhz = hz * 10;
+
+ if (sc->sc_ticks_per_second != agtimer_frequency) {
+ agtimer_set_clockrate(agtimer_frequency);
+ }
+
+ agtimer_setstatclockrate(stathz);
+
+ sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
+ sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
+ pc->pc_ticks_err_sum = 0;
+
+ /* Setup secure and non-secure timer IRQs. */
+ arm_intr_establish_fdt_idx(sc->sc_node, 0, IPL_CLOCK,
+ agtimer_intr, NULL, "tick");
+ arm_intr_establish_fdt_idx(sc->sc_node, 1, IPL_CLOCK,
+ agtimer_intr, NULL, "tick");
+
+ next = agtimer_readcnt64() + sc->sc_ticks_per_intr;
+ pc->pc_nexttickevent = pc->pc_nextstatevent = next;
+
+ reg = agtimer_get_ctrl();
+ reg &= ~GTIMER_CNTP_CTL_IMASK;
+ reg |= GTIMER_CNTP_CTL_ENABLE;
+ agtimer_set_tval(sc->sc_ticks_per_second);
+ agtimer_set_ctrl(reg);
+}
+
+void
+agtimer_delay(u_int usecs)
+{
+ u_int32_t clock, oclock, delta, delaycnt;
+ volatile int j;
+ int csec, usec;
+
+ if (usecs > (0x80000000 / agtimer_frequency)) {
+ csec = usecs / 10000;
+ usec = usecs % 10000;
+
+ delaycnt = (agtimer_frequency / 100) * csec +
+ (agtimer_frequency / 100) * usec / 10000;
+ } else {
+ delaycnt = agtimer_frequency * usecs / 1000000;
+ }
+ if (delaycnt <= 1)
+ for (j = 100; j > 0; j--)
+ ;
+
+ oclock = agtimer_readcnt64();
+ while (1) {
+ for (j = 100; j > 0; j--)
+ ;
+ clock = agtimer_readcnt64();
+ delta = clock - oclock;
+ if (delta > delaycnt)
+ break;
+ }
+}
+
+void
+agtimer_setstatclockrate(int newhz)
+{
+ struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
+ int minint, statint;
+ int s;
+
+ s = splclock();
+
+ statint = sc->sc_ticks_per_second / newhz;
+ /* calculate largest 2^n which is smaller that just over half statint */
+ sc->sc_statvar = 0x40000000; /* really big power of two */
+ minint = statint / 2 + 100;
+ while (sc->sc_statvar > minint)
+ sc->sc_statvar >>= 1;
+
+ sc->sc_statmin = statint - (sc->sc_statvar >> 1);
+
+ splx(s);
+
+ /*
+ * XXX this allows the next stat timer to occur then it switches
+ * to the new frequency. Rather than switching instantly.
+ */
+}
+
+void
+agtimer_startclock(void)
+{
+ struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
+ struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
+ uint64_t nextevent;
+ uint32_t reg;
+
+ nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr;
+ pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
+
+ reg = agtimer_get_ctrl();
+ reg &= ~GTIMER_CNTP_CTL_IMASK;
+ reg |= GTIMER_CNTP_CTL_ENABLE;
+ agtimer_set_tval(sc->sc_ticks_per_second);
+ agtimer_set_ctrl(reg);
+}
+
+void
+agtimer_init(void)
+{
+ uint32_t cntfrq = 0;
+
+ /* XXX: Check for Generic Timer support. */
+ __asm volatile("MRS %x0, CNTFRQ_EL0" : "=r" (cntfrq));
+
+ if (cntfrq != 0) {
+ agtimer_frequency = cntfrq;
+ arm_clock_register(NULL, agtimer_delay, NULL, NULL);
+ }
+}
diff --git a/sys/arch/arm64/dev/ampintc.c b/sys/arch/arm64/dev/ampintc.c
new file mode 100644
index 00000000000..c30a71f801c
--- /dev/null
+++ b/sys/arch/arm64/dev/ampintc.c
@@ -0,0 +1,607 @@
+/* $OpenBSD: ampintc.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2007,2009,2011 Dale Rahn <drahn@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.
+ */
+
+/*
+ * This driver implements the interrupt controller as specified in
+ * DDI0407E_cortex_a9_mpcore_r2p0_trm with the
+ * IHI0048A_gic_architecture_spec_v1_0 underlying specification
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
+/* registers */
+#define ICD_DCR 0x000
+#define ICD_DCR_ES 0x00000001
+#define ICD_DCR_ENS 0x00000002
+
+#define ICD_ICTR 0x004
+#define ICD_ICTR_LSPI_SH 11
+#define ICD_ICTR_LSPI_M 0x1f
+#define ICD_ICTR_CPU_SH 5
+#define ICD_ICTR_CPU_M 0x07
+#define ICD_ICTR_ITL_SH 0
+#define ICD_ICTR_ITL_M 0x1f
+#define ICD_IDIR 0x008
+#define ICD_DIR_PROD_SH 24
+#define ICD_DIR_PROD_M 0xff
+#define ICD_DIR_REV_SH 12
+#define ICD_DIR_REV_M 0xfff
+#define ICD_DIR_IMP_SH 0
+#define ICD_DIR_IMP_M 0xfff
+
+#define IRQ_TO_REG32(i) (((i) >> 5) & 0x7)
+#define IRQ_TO_REG32BIT(i) ((i) & 0x1f)
+#define IRQ_TO_REG4(i) (((i) >> 2) & 0x3f)
+#define IRQ_TO_REG4BIT(i) ((i) & 0x3)
+#define IRQ_TO_REG16(i) (((i) >> 4) & 0xf)
+#define IRQ_TO_REGBIT_S(i) 8
+#define IRQ_TO_REG4BIT_M(i) 8
+
+#define ICD_ISRn(i) (0x080 + (IRQ_TO_REG32(i) * 4))
+#define ICD_ISERn(i) (0x100 + (IRQ_TO_REG32(i) * 4))
+#define ICD_ICERn(i) (0x180 + (IRQ_TO_REG32(i) * 4))
+#define ICD_ISPRn(i) (0x200 + (IRQ_TO_REG32(i) * 4))
+#define ICD_ICPRn(i) (0x280 + (IRQ_TO_REG32(i) * 4))
+#define ICD_ABRn(i) (0x300 + (IRQ_TO_REG32(i) * 4))
+#define ICD_IPRn(i) (0x400 + (i))
+#define ICD_IPTRn(i) (0x800 + (i))
+#define ICD_ICRn(i) (0xC00 + (IRQ_TO_REG16(i) * 4))
+/*
+ * what about (ppi|spi)_status
+ */
+#define ICD_PPI 0xD00
+#define ICD_PPI_GTIMER (1 << 11)
+#define ICD_PPI_FIQ (1 << 12)
+#define ICD_PPI_PTIMER (1 << 13)
+#define ICD_PPI_PWDOG (1 << 14)
+#define ICD_PPI_IRQ (1 << 15)
+#define ICD_SPI_BASE 0xD04
+#define ICD_SPIn(i) (ICD_SPI_BASE + ((i) * 4))
+
+
+#define ICD_SGIR 0xF00
+
+#define ICD_PERIPH_ID_0 0xFD0
+#define ICD_PERIPH_ID_1 0xFD4
+#define ICD_PERIPH_ID_2 0xFD8
+#define ICD_PERIPH_ID_3 0xFDC
+#define ICD_PERIPH_ID_4 0xFE0
+#define ICD_PERIPH_ID_5 0xFE4
+#define ICD_PERIPH_ID_6 0xFE8
+#define ICD_PERIPH_ID_7 0xFEC
+
+#define ICD_COMP_ID_0 0xFEC
+#define ICD_COMP_ID_1 0xFEC
+#define ICD_COMP_ID_2 0xFEC
+#define ICD_COMP_ID_3 0xFEC
+
+
+#define ICPICR 0x00
+#define ICPIPMR 0x04
+/* XXX - must left justify bits to 0 - 7 */
+#define ICMIPMR_SH 4
+#define ICPBPR 0x08
+#define ICPIAR 0x0C
+#define ICPIAR_IRQ_SH 0
+#define ICPIAR_IRQ_M 0x3ff
+#define ICPIAR_CPUID_SH 10
+#define ICPIAR_CPUID_M 0x7
+#define ICPIAR_NO_PENDING_IRQ ICPIAR_IRQ_M
+#define ICPEOIR 0x10
+#define ICPPRP 0x14
+#define ICPHPIR 0x18
+#define ICPIIR 0xFC
+
+/*
+ * what about periph_id and component_id
+ */
+
+#define IRQ_ENABLE 1
+#define IRQ_DISABLE 0
+
+struct ampintc_softc {
+ struct device sc_dev;
+ struct intrq *sc_ampintc_handler;
+ int sc_nintr;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_d_ioh, sc_p_ioh;
+ struct evcount sc_spur;
+ struct interrupt_controller sc_ic;
+};
+struct ampintc_softc *ampintc;
+
+
+struct intrhand {
+ TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
+ int (*ih_func)(void *); /* handler */
+ void *ih_arg; /* arg for handler */
+ int ih_ipl; /* IPL_* */
+ int ih_irq; /* IRQ number */
+ struct evcount ih_count;
+ char *ih_name;
+};
+
+struct intrq {
+ TAILQ_HEAD(, intrhand) iq_list; /* handler list */
+ int iq_irq; /* IRQ to mask while handling */
+ int iq_levels; /* IPL_*'s this IRQ has */
+ int iq_ist; /* share type */
+};
+
+
+int ampintc_match(struct device *, void *, void *);
+void ampintc_attach(struct device *, struct device *, void *);
+int ampintc_spllower(int);
+void ampintc_splx(int);
+int ampintc_splraise(int);
+void ampintc_setipl(int);
+void ampintc_calc_mask(void);
+void *ampintc_intr_establish(int, int, int (*)(void *), void *,
+ char *);
+void *ampintc_intr_establish_ext(int, int, int (*)(void *), void *,
+ char *);
+void *ampintc_intr_establish_fdt(void *, int *, int,
+ int (*)(void *), void *, char *);
+void ampintc_intr_disestablish(void *);
+void ampintc_irq_handler(void *);
+const char *ampintc_intr_string(void *);
+uint32_t ampintc_iack(void);
+void ampintc_eoi(uint32_t);
+void ampintc_set_priority(int, int);
+void ampintc_intr_enable(int);
+void ampintc_intr_disable(int);
+void ampintc_route(int, int , int);
+
+struct cfattach ampintc_ca = {
+ sizeof (struct ampintc_softc), ampintc_match, ampintc_attach
+};
+
+struct cfdriver ampintc_cd = {
+ NULL, "ampintc", DV_DULL
+};
+
+static char *ampintc_compatibles[] = {
+ "arm,cortex-a7-gic",
+ "arm,cortex-a9-gic",
+ "arm,cortex-a15-gic",
+ NULL
+};
+
+int
+ampintc_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+ int i;
+
+ for (i = 0; ampintc_compatibles[i]; i++)
+ if (OF_is_compatible(faa->fa_node, ampintc_compatibles[i]))
+ return (1);
+
+ return (0);
+}
+
+void
+ampintc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ampintc_softc *sc = (struct ampintc_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ int i, nintr;
+
+ ampintc = sc;
+
+ arm_init_smask();
+
+ sc->sc_iot = faa->fa_iot;
+
+ /* First row: ICD */
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+ faa->fa_reg[0].size, 0, &sc->sc_d_ioh))
+ panic("%s: ICD bus_space_map failed!", __func__);
+
+ /* Second row: ICP */
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
+ faa->fa_reg[1].size, 0, &sc->sc_p_ioh))
+ panic("%s: ICP bus_space_map failed!", __func__);
+
+ evcount_attach(&sc->sc_spur, "irq1023/spur", NULL);
+
+ nintr = 32 * (bus_space_read_4(sc->sc_iot, sc->sc_d_ioh,
+ ICD_ICTR) & ICD_ICTR_ITL_M);
+ nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */
+ sc->sc_nintr = nintr;
+ printf(" nirq %d\n", nintr);
+
+ /* Disable all interrupts, clear all pending */
+ for (i = 0; i < nintr/32; i++) {
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
+ ICD_ICERn(i*32), ~0);
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
+ ICD_ICPRn(i*32), ~0);
+ }
+ for (i = 0; i < nintr; i++) {
+ /* lowest priority ?? */
+ bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 0xff);
+ /* target no cpus */
+ bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(i), 0);
+ }
+ for (i = 2; i < nintr/16; i++) {
+ /* irq 32 - N */
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(i*16), 0);
+ }
+
+ /* software reset of the part? */
+ /* set protection bit (kernel only)? */
+
+ /* XXX - check power saving bit */
+
+ sc->sc_ampintc_handler = mallocarray(nintr,
+ sizeof(*sc->sc_ampintc_handler), M_DEVBUF, M_ZERO | M_NOWAIT);
+ for (i = 0; i < nintr; i++) {
+ TAILQ_INIT(&sc->sc_ampintc_handler[i].iq_list);
+ }
+
+ ampintc_setipl(IPL_HIGH); /* XXX ??? */
+ ampintc_calc_mask();
+
+ /* insert self as interrupt handler */
+ arm_set_intr_handler(ampintc_splraise, ampintc_spllower, ampintc_splx,
+ ampintc_setipl, ampintc_intr_establish_ext,
+ ampintc_intr_disestablish, ampintc_irq_handler);
+
+ /* enable interrupts */
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
+ bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
+ enable_interrupts();
+
+ sc->sc_ic.ic_node = faa->fa_node;
+ sc->sc_ic.ic_cookie = self;
+ sc->sc_ic.ic_establish = ampintc_intr_establish_fdt;
+ sc->sc_ic.ic_disestablish = ampintc_intr_disestablish;
+ arm_intr_register_fdt(&sc->sc_ic);
+}
+
+void
+ampintc_set_priority(int irq, int pri)
+{
+ struct ampintc_softc *sc = ampintc;
+ uint32_t prival;
+
+ /*
+ * We only use 16 (13 really) interrupt priorities,
+ * and a CPU is only required to implement bit 4-7 of each field
+ * so shift into the top bits.
+ * also low values are higher priority thus IPL_HIGH - pri
+ */
+ prival = (IPL_HIGH - pri) << ICMIPMR_SH;
+ bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(irq), prival);
+}
+
+void
+ampintc_setipl(int new)
+{
+ struct cpu_info *ci = curcpu();
+ struct ampintc_softc *sc = ampintc;
+ int psw;
+
+ /* disable here is only to keep hardware in sync with ci->ci_cpl */
+ psw = disable_interrupts();
+ ci->ci_cpl = new;
+
+ /* low values are higher priority thus IPL_HIGH - pri */
+ bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPIPMR,
+ (IPL_HIGH - new) << ICMIPMR_SH);
+ restore_interrupts(psw);
+}
+
+void
+ampintc_intr_enable(int irq)
+{
+ struct ampintc_softc *sc = ampintc;
+
+#ifdef DEBUG
+ printf("enable irq %d register %x bitmask %08x\n",
+ irq, ICD_ISERn(irq), 1 << IRQ_TO_REG32BIT(irq));
+#endif
+
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ISERn(irq),
+ 1 << IRQ_TO_REG32BIT(irq));
+}
+
+void
+ampintc_intr_disable(int irq)
+{
+ struct ampintc_softc *sc = ampintc;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICERn(irq),
+ 1 << IRQ_TO_REG32BIT(irq));
+}
+
+
+void
+ampintc_calc_mask(void)
+{
+ struct cpu_info *ci = curcpu();
+ struct ampintc_softc *sc = ampintc;
+ struct intrhand *ih;
+ int irq;
+
+ for (irq = 0; irq < sc->sc_nintr; irq++) {
+ int max = IPL_NONE;
+ int min = IPL_HIGH;
+ TAILQ_FOREACH(ih, &sc->sc_ampintc_handler[irq].iq_list,
+ ih_list) {
+ if (ih->ih_ipl > max)
+ max = ih->ih_ipl;
+
+ if (ih->ih_ipl < min)
+ min = ih->ih_ipl;
+ }
+
+ if (sc->sc_ampintc_handler[irq].iq_irq == max) {
+ continue;
+ }
+ sc->sc_ampintc_handler[irq].iq_irq = max;
+
+ if (max == IPL_NONE)
+ min = IPL_NONE;
+
+ /* Enable interrupts at lower levels, clear -> enable */
+ /* Set interrupt priority/enable */
+ if (min != IPL_NONE) {
+ ampintc_set_priority(irq, min);
+ ampintc_intr_enable(irq);
+ ampintc_route(irq, IRQ_ENABLE, 0);
+ } else {
+ ampintc_intr_disable(irq);
+ ampintc_route(irq, IRQ_DISABLE, 0);
+
+ }
+ }
+ ampintc_setipl(ci->ci_cpl);
+}
+
+void
+ampintc_splx(int new)
+{
+ struct cpu_info *ci = curcpu();
+
+ if (ci->ci_ipending & arm_smask[new])
+ arm_do_pending_intr(new);
+
+ ampintc_setipl(new);
+}
+
+int
+ampintc_spllower(int new)
+{
+ struct cpu_info *ci = curcpu();
+ int old = ci->ci_cpl;
+ ampintc_splx(new);
+ return (old);
+}
+
+int
+ampintc_splraise(int new)
+{
+ struct cpu_info *ci = curcpu();
+ int old;
+ old = ci->ci_cpl;
+
+ /*
+ * setipl must always be called because there is a race window
+ * where the variable is updated before the mask is set
+ * an interrupt occurs in that window without the mask always
+ * being set, the hardware might not get updated on the next
+ * splraise completely messing up spl protection.
+ */
+ if (old > new)
+ new = old;
+
+ ampintc_setipl(new);
+
+ return (old);
+}
+
+
+uint32_t
+ampintc_iack(void)
+{
+ uint32_t intid;
+ struct ampintc_softc *sc = ampintc;
+
+ intid = bus_space_read_4(sc->sc_iot, sc->sc_p_ioh, ICPIAR);
+
+ return (intid);
+}
+
+void
+ampintc_eoi(uint32_t eoi)
+{
+ struct ampintc_softc *sc = ampintc;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPEOIR, eoi);
+}
+
+void
+ampintc_route(int irq, int enable, int cpu)
+{
+ uint8_t val;
+ struct ampintc_softc *sc = ampintc;
+
+ val = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq));
+ if (enable == IRQ_ENABLE)
+ val |= (1 << cpu);
+ else
+ val &= ~(1 << cpu);
+ bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), val);
+}
+
+void
+ampintc_irq_handler(void *frame)
+{
+ struct ampintc_softc *sc = ampintc;
+ struct intrhand *ih;
+ void *arg;
+ uint32_t iack_val;
+ int irq, pri, s;
+
+ iack_val = ampintc_iack();
+#ifdef DEBUG_INTC
+ if (iack_val != 27)
+ printf("irq %d fired\n", iack_val);
+ else {
+ static int cnt = 0;
+ if ((cnt++ % 100) == 0) {
+ printf("irq %d fired * _100\n", iack_val);
+#ifdef DDB
+ Debugger();
+#endif
+ }
+
+ }
+#endif
+
+ if (iack_val == 1023) {
+ sc->sc_spur.ec_count++;
+ return;
+ }
+ irq = iack_val & ((1 << sc->sc_nintr) - 1);
+
+ pri = sc->sc_ampintc_handler[irq].iq_irq;
+ s = ampintc_splraise(pri);
+ TAILQ_FOREACH(ih, &sc->sc_ampintc_handler[irq].iq_list, ih_list) {
+ if (ih->ih_arg != 0)
+ arg = ih->ih_arg;
+ else
+ arg = frame;
+
+ if (ih->ih_func(arg))
+ ih->ih_count.ec_count++;
+
+ }
+ ampintc_eoi(iack_val);
+
+ ampintc_splx(s);
+}
+
+void *
+ampintc_intr_establish_ext(int irqno, int level, int (*func)(void *),
+ void *arg, char *name)
+{
+ return ampintc_intr_establish(irqno+32, level, func, arg, name);
+}
+
+void *
+ampintc_intr_establish_fdt(void *cookie, int *cell, int level,
+ int (*func)(void *), void *arg, char *name)
+{
+ struct ampintc_softc *sc = (struct ampintc_softc *)cookie;
+ int irq;
+
+ /* 2nd cell contains the interrupt number */
+ irq = cell[1];
+
+ /* 1st cell contains type: 0 SPI (32-X), 1 PPI (16-31) */
+ if (cell[0] == 0)
+ irq += 32;
+ else if (cell[0] == 1)
+ irq += 16;
+ else
+ panic("%s: bogus interrupt type", sc->sc_dev.dv_xname);
+
+ return ampintc_intr_establish(irq, level, func, arg, name);
+}
+
+void *
+ampintc_intr_establish(int irqno, int level, int (*func)(void *),
+ void *arg, char *name)
+{
+ struct ampintc_softc *sc = ampintc;
+ struct intrhand *ih;
+ int psw;
+
+ if (irqno < 0 || irqno >= sc->sc_nintr)
+ panic("ampintc_intr_establish: bogus irqnumber %d: %s",
+ irqno, name);
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
+ ih->ih_func = func;
+ ih->ih_arg = arg;
+ ih->ih_ipl = level;
+ ih->ih_irq = irqno;
+ ih->ih_name = name;
+
+ psw = disable_interrupts();
+
+ TAILQ_INSERT_TAIL(&sc->sc_ampintc_handler[irqno].iq_list, ih, ih_list);
+
+ if (name != NULL)
+ evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+#ifdef DEBUG_INTC
+ printf("ampintc_intr_establish irq %d level %d [%s]\n", irqno, level,
+ name);
+#endif
+ ampintc_calc_mask();
+
+ restore_interrupts(psw);
+ return (ih);
+}
+
+void
+ampintc_intr_disestablish(void *cookie)
+{
+ struct ampintc_softc *sc = ampintc;
+ struct intrhand *ih = cookie;
+ int psw;
+
+#ifdef DEBUG_INTC
+ printf("ampintc_intr_disestablish irq %d level %d [%s]\n",
+ ih->ih_irq, ih->ih_ipl, ih->ih_name);
+#endif
+
+ psw = disable_interrupts();
+
+ TAILQ_REMOVE(&sc->sc_ampintc_handler[ih->ih_irq].iq_list, ih, ih_list);
+ if (ih->ih_name != NULL)
+ evcount_detach(&ih->ih_count);
+ free(ih, M_DEVBUF, sizeof(*ih));
+
+ ampintc_calc_mask();
+
+ restore_interrupts(psw);
+}
+
+const char *
+ampintc_intr_string(void *cookie)
+{
+ struct intrhand *ih = (struct intrhand *)cookie;
+ static char irqstr[1 + sizeof("ampintc irq ") + 4];
+
+ snprintf(irqstr, sizeof irqstr, "ampintc irq %d", ih->ih_irq);
+ return irqstr;
+}
diff --git a/sys/arch/arm64/dev/arm64_bus_space.c b/sys/arch/arm64/dev/arm64_bus_space.c
new file mode 100644
index 00000000000..05d5c886ce3
--- /dev/null
+++ b/sys/arch/arm64/dev/arm64_bus_space.c
@@ -0,0 +1,312 @@
+/* $OpenBSD: arm64_bus_space.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
+ *
+ * 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 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.
+ *
+ */
+
+/*
+ * Simple generic bus access primitives.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+uint8_t
+generic_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint8_t *)(h + o);
+}
+
+uint16_t
+generic_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint16_t *)(h + o);
+}
+
+uint32_t
+generic_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint32_t *)(h + o);
+}
+
+uint64_t
+generic_space_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint64_t *)(h + o);
+}
+
+void
+generic_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint8_t v)
+{
+ *(volatile uint8_t *)(h + o) = v;
+}
+
+void
+generic_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint16_t v)
+{
+ *(volatile uint16_t *)(h + o) = v;
+}
+
+void
+generic_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint32_t v)
+{
+ *(volatile uint32_t *)(h + o) = v;
+}
+
+void
+generic_space_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint64_t v)
+{
+ *(volatile uint64_t *)(h + o) = v;
+}
+
+void
+generic_space_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + o);
+ len >>= 1;
+ while (len-- != 0) {
+ *(uint16_t *)buf = *addr;
+ buf += 2;
+ }
+}
+
+void
+generic_space_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + o);
+ len >>= 1;
+ while (len-- != 0) {
+ *addr = *(uint16_t *)buf;
+ buf += 2;
+ }
+}
+
+void
+generic_space_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + o);
+ len >>= 2;
+ while (len-- != 0) {
+ *(uint32_t *)buf = *addr;
+ buf += 4;
+ }
+}
+
+void
+generic_space_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + o);
+ len >>= 2;
+ while (len-- != 0) {
+ *addr = *(uint32_t *)buf;
+ buf += 4;
+ }
+}
+
+void
+generic_space_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + o);
+ len >>= 3;
+ while (len-- != 0) {
+ *(uint64_t *)buf = *addr;
+ buf += 8;
+ }
+}
+
+void
+generic_space_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + o);
+ len >>= 3;
+ while (len-- != 0) {
+ *addr = *(uint64_t *)buf;
+ buf += 8;
+ }
+}
+
+int
+generic_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ *bshp = t->bus_base + offs;
+ return 0;
+}
+
+void
+generic_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
+{
+}
+
+int
+generic_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
+ bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
+{
+ *nbshp = bsh + offset;
+ return 0;
+}
+
+void *
+generic_space_vaddr(bus_space_tag_t t, bus_space_handle_t h)
+{
+ return (void *)h;
+}
+
+uint8_t
+a4x_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint8_t *)(h + (o*4));
+}
+
+uint16_t
+a4x_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint16_t *)(h + (o*4));
+}
+
+uint32_t
+a4x_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint32_t *)(h + (o*4));
+}
+
+uint64_t
+a4x_space_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
+{
+ return *(volatile uint64_t *)(h + (o*4));
+}
+
+void
+a4x_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint8_t v)
+{
+ *(volatile uint8_t *)(h + (o*4)) = v;
+}
+
+void
+a4x_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint16_t v)
+{
+ *(volatile uint16_t *)(h + (o*4)) = v;
+}
+
+void
+a4x_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint32_t v)
+{
+ *(volatile uint32_t *)(h + (o*4)) = v;
+}
+
+void
+a4x_space_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
+ uint64_t v)
+{
+ *(volatile uint64_t *)(h + (o*4)) = v;
+}
+
+void
+a4x_space_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + (o*4));
+ len >>= 1;
+ while (len-- != 0) {
+ *(uint16_t *)buf = *addr;
+ buf += 2;
+ }
+}
+
+void
+a4x_space_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint16_t *addr = (volatile uint16_t *)(h + (o*4));
+ len >>= 1;
+ while (len-- != 0) {
+ *addr = *(uint16_t *)buf;
+ buf += 2;
+ }
+}
+
+void
+a4x_space_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + (o*4));
+ len >>= 2;
+ while (len-- != 0) {
+ *(uint32_t *)buf = *addr;
+ buf += 4;
+ }
+}
+
+void
+a4x_space_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint32_t *addr = (volatile uint32_t *)(h + (o*4));
+ len >>= 2;
+ while (len-- != 0) {
+ *addr = *(uint32_t *)buf;
+ buf += 4;
+ }
+}
+
+void
+a4x_space_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + (o*4));
+ len >>= 3;
+ while (len-- != 0) {
+ *(uint64_t *)buf = *addr;
+ buf += 8;
+ }
+}
+
+void
+a4x_space_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
+ const uint8_t *buf, bus_size_t len)
+{
+ volatile uint64_t *addr = (volatile uint64_t *)(h + (o*4));
+ len >>= 3;
+ while (len-- != 0) {
+ *addr = *(uint64_t *)buf;
+ buf += 8;
+ }
+}
+
diff --git a/sys/arch/arm64/dev/com_fdt.c b/sys/arch/arm64/dev/com_fdt.c
new file mode 100644
index 00000000000..f63f33f44e9
--- /dev/null
+++ b/sys/arch/arm64/dev/com_fdt.c
@@ -0,0 +1,196 @@
+/* $OpenBSD: com_fdt.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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/systm.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#include <dev/cons.h>
+
+#include <arm64/arm64/arm64var.h>
+#include <arm64/arm64/arm64_machdep.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_clock.h>
+#include <dev/ofw/ofw_pinctrl.h>
+
+#define com_usr 31 /* Synopsys DesignWare UART */
+
+int com_fdt_match(struct device *, void *, void *);
+void com_fdt_attach(struct device *, struct device *, void *);
+int com_fdt_intr_designware(void *);
+
+extern int comcnspeed;
+extern int comcnmode;
+
+struct com_fdt_softc {
+ struct com_softc sc;
+ struct bus_space sc_iot;
+};
+
+struct cfattach com_fdt_ca = {
+ sizeof (struct com_fdt_softc), com_fdt_match, com_fdt_attach
+};
+
+int com_fdt_cngetc(dev_t);
+void com_fdt_cnputc(dev_t, int);
+void com_fdt_cnpollc(dev_t, int);
+
+struct consdev com_fdt_cons = {
+ NULL, NULL, com_fdt_cngetc, com_fdt_cnputc, com_fdt_cnpollc, NULL,
+ NODEV, CN_LOWPRI
+};
+
+void
+com_fdt_init_cons(void)
+{
+ struct fdt_reg reg;
+ void *node;
+
+ if ((node = fdt_find_cons("brcm,bcm2835-aux-uart")) == NULL &&
+ (node = fdt_find_cons("snps,dw-apb-uart")) == NULL &&
+ (node = fdt_find_cons("ti,omap3-uart")) == NULL &&
+ (node = fdt_find_cons("ti,omap4-uart")) == NULL)
+ return;
+ if (fdt_get_reg(node, 0, &reg))
+ return;
+
+ /*
+ * Figuring out the clock frequency is rather complicated as
+ * on many SoCs this requires traversing a fair amount of the
+ * clock tree. Instead we rely on the firmware to set up the
+ * console for us and bypass the cominit() call that
+ * comcnattach() does by doing the minimal setup here.
+ */
+
+ comconsiot = &arm64_a4x_bs_tag;
+ if (bus_space_map(comconsiot, reg.addr, reg.size, 0, &comconsioh))
+ return;
+
+ comconsrate = comcnspeed;
+ comconscflag = comcnmode;
+ cn_tab = &com_fdt_cons;
+}
+
+int
+com_fdt_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return (OF_is_compatible(faa->fa_node, "brcm,bcm2835-aux-uart") ||
+ OF_is_compatible(faa->fa_node, "snps,dw-apb-uart") ||
+ OF_is_compatible(faa->fa_node, "ti,omap3-uart") ||
+ OF_is_compatible(faa->fa_node, "ti,omap4-uart"));
+}
+
+void
+com_fdt_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct com_fdt_softc *sc = (struct com_fdt_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ int (*intr)(void *) = comintr;
+ uint32_t freq;
+
+ if (faa->fa_nreg < 1)
+ return;
+
+ clock_enable(faa->fa_node, NULL);
+
+ /*
+ * Determine the clock frequency after enabling the clock.
+ * This gives the clock code a chance to configure the
+ * appropriate frequency for us.
+ */
+ freq = OF_getpropint(faa->fa_node, "clock-frequency", 0);
+ if (freq == 0)
+ freq = clock_get_frequency(faa->fa_node, NULL);
+
+ /*
+ * XXX This sucks. We need to get rid of the a4x bus tag
+ * altogether. For this we will need to change com(4).
+ */
+ sc->sc_iot = arm64_a4x_bs_tag;
+ sc->sc_iot.bus_base = faa->fa_iot->bus_base;
+ sc->sc_iot.bus_private = faa->fa_iot->bus_private;
+ sc->sc_iot._space_map = faa->fa_iot->_space_map;
+
+ sc->sc.sc_iot = &sc->sc_iot;
+ sc->sc.sc_iobase = faa->fa_reg[0].addr;
+ sc->sc.sc_uarttype = COM_UART_16550;
+ sc->sc.sc_frequency = freq ? freq : COM_FREQ;
+
+ if (OF_is_compatible(faa->fa_node, "snps,dw-apb-uart"))
+ intr = com_fdt_intr_designware;
+
+ if (OF_is_compatible(faa->fa_node, "ti,omap3-uart") ||
+ OF_is_compatible(faa->fa_node, "ti,omap4-uart"))
+ sc->sc.sc_uarttype = COM_UART_TI16750;
+
+ if (stdout_node == faa->fa_node) {
+ SET(sc->sc.sc_hwflags, COM_HW_CONSOLE);
+ SET(sc->sc.sc_swflags, COM_SW_SOFTCAR);
+ comconsfreq = sc->sc.sc_frequency;
+ }
+
+ if (bus_space_map(sc->sc.sc_iot, sc->sc.sc_iobase,
+ faa->fa_reg[0].size, 0, &sc->sc.sc_ioh)) {
+ printf("%s: bus_space_map failed\n", __func__);
+ return;
+ }
+
+ pinctrl_byname(faa->fa_node, "default");
+
+ com_attach_subr(&sc->sc);
+
+ arm_intr_establish_fdt(faa->fa_node, IPL_TTY, intr,
+ sc, sc->sc.sc_dev.dv_xname);
+}
+
+int
+com_fdt_intr_designware(void *cookie)
+{
+ struct com_softc *sc = cookie;
+
+ bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_usr);
+
+ return comintr(sc);
+}
+
+int
+com_fdt_cngetc(dev_t dev)
+{
+ return com_common_getc(comconsiot, comconsioh);
+}
+
+void
+com_fdt_cnputc(dev_t dev, int c)
+{
+ com_common_putc(comconsiot, comconsioh, c);
+}
+
+void
+com_fdt_cnpollc(dev_t dev, int on)
+{
+}
diff --git a/sys/arch/arm64/dev/mainbus.c b/sys/arch/arm64/dev/mainbus.c
new file mode 100644
index 00000000000..fea6a960510
--- /dev/null
+++ b/sys/arch/arm64/dev/mainbus.c
@@ -0,0 +1,216 @@
+/* $OpenBSD: mainbus.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/fdt.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#include <arm64/arm64/arm64var.h>
+#include <arm64/dev/mainbus.h>
+
+int mainbus_match(struct device *, void *, void *);
+void mainbus_attach(struct device *, struct device *, void *);
+
+void mainbus_attach_node(struct device *, int);
+
+struct mainbus_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_dma_tag_t sc_dmat;
+ int sc_acells;
+ int sc_scells;
+ int *sc_ranges;
+ int sc_rangeslen;
+};
+
+struct cfattach mainbus_ca = {
+ sizeof(struct mainbus_softc), mainbus_match, mainbus_attach, NULL,
+ config_activate_children
+};
+
+struct cfdriver mainbus_cd = {
+ NULL, "mainbus", DV_DULL
+};
+
+struct machine_bus_dma_tag mainbus_dma_tag = {
+ NULL,
+ _dmamap_create,
+ _dmamap_destroy,
+ _dmamap_load,
+ _dmamap_load_mbuf,
+ _dmamap_load_uio,
+ _dmamap_load_raw,
+ _dmamap_load_buffer,
+ _dmamap_unload,
+ _dmamap_sync,
+ _dmamem_alloc,
+ _dmamem_free,
+ _dmamem_map,
+ _dmamem_unmap,
+ _dmamem_mmap,
+};
+
+/*
+ * Mainbus takes care of FDT and non-FDT machines, so we
+ * always attach.
+ */
+int
+mainbus_match(struct device *parent, void *cfdata, void *aux)
+{
+ return (1);
+}
+
+extern char *hw_prod;
+
+void
+mainbus_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mainbus_softc *sc = (struct mainbus_softc *)self;
+ char buffer[128];
+ int node, len;
+
+ if ((node = OF_peer(0)) == 0)
+ panic("mainbus: no device tree");
+
+ arm_intr_init_fdt();
+
+ sc->sc_iot = &arm64_bs_tag;
+ sc->sc_dmat = &mainbus_dma_tag;
+ sc->sc_acells = OF_getpropint(OF_peer(0), "#address-cells", 1);
+ sc->sc_scells = OF_getpropint(OF_peer(0), "#size-cells", 1);
+
+ if ((len = OF_getprop(node, "model", buffer, sizeof(buffer))) > 0) {
+ printf(": %s\n", buffer);
+ hw_prod = malloc(len, M_DEVBUF, M_NOWAIT);
+ if (hw_prod)
+ strlcpy(hw_prod, buffer, len);
+ } else
+ printf(": unknown model\n");
+
+ /* Attach CPU first. */
+ mainbus_legacy_found(self, "cpu");
+
+ /* TODO: Scan for interrupt controllers and attach them first? */
+
+ sc->sc_rangeslen = OF_getproplen(OF_peer(0), "ranges");
+ if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) {
+ sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(OF_peer(0), "ranges", sc->sc_ranges,
+ sc->sc_rangeslen);
+ }
+
+ /* Scan the whole tree. */
+ for (node = OF_child(node);
+ node != 0;
+ node = OF_peer(node))
+ {
+ mainbus_attach_node(self, node);
+ }
+}
+
+/*
+ * Look for a driver that wants to be attached to this node.
+ */
+void
+mainbus_attach_node(struct device *self, int node)
+{
+ struct mainbus_softc *sc = (struct mainbus_softc *)self;
+ struct fdt_attach_args fa;
+ char buffer[128];
+ int i, len, line;
+ uint32_t *cell, *reg;
+
+ if (!OF_getprop(node, "compatible", buffer, sizeof(buffer)))
+ return;
+
+ if (OF_getprop(node, "status", buffer, sizeof(buffer)))
+ if (!strcmp(buffer, "disabled"))
+ return;
+
+ memset(&fa, 0, sizeof(fa));
+ fa.fa_name = "";
+ fa.fa_node = node;
+ fa.fa_iot = sc->sc_iot;
+ fa.fa_dmat = sc->sc_dmat;
+ fa.fa_acells = sc->sc_acells;
+ fa.fa_scells = sc->sc_scells;
+
+ len = OF_getproplen(node, "reg");
+ line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
+ if (len > 0 && (len % line) == 0) {
+ reg = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "reg", reg, len);
+
+ fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
+ M_DEVBUF, M_WAITOK);
+ fa.fa_nreg = (len / line);
+
+ for (i = 0, cell = reg; i < len / line; i++) {
+ if (sc->sc_acells >= 1)
+ fa.fa_reg[i].addr = cell[0];
+ if (sc->sc_acells == 2) {
+ fa.fa_reg[i].addr <<= 32;
+ fa.fa_reg[i].addr |= cell[1];
+ }
+ cell += sc->sc_acells;
+ if (sc->sc_scells >= 1)
+ fa.fa_reg[i].size = cell[0];
+ if (sc->sc_scells == 2) {
+ fa.fa_reg[i].size <<= 32;
+ fa.fa_reg[i].size |= cell[1];
+ }
+ cell += sc->sc_scells;
+ }
+
+ free(reg, M_TEMP, len);
+ }
+
+ len = OF_getproplen(node, "interrupts");
+ if (len > 0 && (len % sizeof(uint32_t)) == 0) {
+ fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
+ fa.fa_nintr = len / sizeof(uint32_t);
+
+ OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
+ }
+
+ /* TODO: attach the device's clocks first? */
+
+ config_found(self, &fa, NULL);
+
+ free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
+ free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
+}
+
+/*
+ * Legacy support for SoCs that do not use FDT.
+ */
+void
+mainbus_legacy_found(struct device *self, char *name)
+{
+ union mainbus_attach_args ma;
+
+ memset(&ma, 0, sizeof(ma));
+ ma.ma_name = name;
+
+ config_found(self, &ma, NULL);
+}
diff --git a/sys/arch/arm64/dev/mainbus.h b/sys/arch/arm64/dev/mainbus.h
new file mode 100644
index 00000000000..9bafb71e4f7
--- /dev/null
+++ b/sys/arch/arm64/dev/mainbus.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: mainbus.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef __MAINBUS_H__
+#define __MAINBUS_H__
+
+/* Passed as third arg to attach functions. */
+union mainbus_attach_args {
+ const char *ma_name;
+ struct fdt_attach_args ma_faa;
+};
+
+void mainbus_legacy_found(struct device *, char *);
+
+#endif /* __MAINBUS_H__ */
diff --git a/sys/arch/arm64/dev/pluart.c b/sys/arch/arm64/dev/pluart.c
new file mode 100644
index 00000000000..f81154eaa2c
--- /dev/null
+++ b/sys/arch/arm64/dev/pluart.c
@@ -0,0 +1,901 @@
+/* $OpenBSD: pluart.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
+ * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <sys/syslog.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/select.h>
+#include <sys/kernel.h>
+
+#include <dev/cons.h>
+
+#ifdef DDB
+#include <ddb/db_var.h>
+#endif
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <arm64/arm64/arm64var.h>
+#include <arm64/arm64/arm64_machdep.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
+#define DEVUNIT(x) (minor(x) & 0x7f)
+#define DEVCUA(x) (minor(x) & 0x80)
+
+#define UART_DR 0x00 /* Data register */
+#define UART_DR_DATA(x) ((x) & 0xf)
+#define UART_DR_FE (1 << 8) /* Framing error */
+#define UART_DR_PE (1 << 9) /* Parity error */
+#define UART_DR_BE (1 << 10) /* Break error */
+#define UART_DR_OE (1 << 11) /* Overrun error */
+#define UART_RSR 0x04 /* Receive status register */
+#define UART_RSR_FE (1 << 0) /* Framing error */
+#define UART_RSR_PE (1 << 1) /* Parity error */
+#define UART_RSR_BE (1 << 2) /* Break error */
+#define UART_RSR_OE (1 << 3) /* Overrun error */
+#define UART_ECR 0x04 /* Error clear register */
+#define UART_ECR_FE (1 << 0) /* Framing error */
+#define UART_ECR_PE (1 << 1) /* Parity error */
+#define UART_ECR_BE (1 << 2) /* Break error */
+#define UART_ECR_OE (1 << 3) /* Overrun error */
+#define UART_FR 0x18 /* Flag register */
+#define UART_FR_CTS (1 << 0) /* Clear to send */
+#define UART_FR_DSR (1 << 1) /* Data set ready */
+#define UART_FR_DCD (1 << 2) /* Data carrier detect */
+#define UART_FR_BUSY (1 << 3) /* UART busy */
+#define UART_FR_RXFE (1 << 4) /* Receive FIFO empty */
+#define UART_FR_TXFF (1 << 5) /* Transmit FIFO full */
+#define UART_FR_RXFF (1 << 6) /* Receive FIFO full */
+#define UART_FR_TXFE (1 << 7) /* Transmit FIFO empty */
+#define UART_FR_RI (1 << 8) /* Ring indicator */
+#define UART_ILPR 0x20 /* IrDA low-power counter register */
+#define UART_ILPR_ILPDVSR ((x) & 0xf) /* IrDA low-power divisor */
+#define UART_IBRD 0x24 /* Integer baud rate register */
+#define UART_IBRD_DIVINT ((x) & 0xff) /* Integer baud rate divisor */
+#define UART_FBRD 0x28 /* Fractional baud rate register */
+#define UART_FBRD_DIVFRAC ((x) & 0x3f) /* Fractional baud rate divisor */
+#define UART_LCR_H 0x2c /* Line control register */
+#define UART_LCR_H_BRK (1 << 0) /* Send break */
+#define UART_LCR_H_PEN (1 << 1) /* Parity enable */
+#define UART_LCR_H_EPS (1 << 2) /* Even parity select */
+#define UART_LCR_H_STP2 (1 << 3) /* Two stop bits select */
+#define UART_LCR_H_FEN (1 << 4) /* Enable FIFOs */
+#define UART_LCR_H_WLEN5 (0x0 << 5) /* Word length: 5 bits */
+#define UART_LCR_H_WLEN6 (0x1 << 5) /* Word length: 6 bits */
+#define UART_LCR_H_WLEN7 (0x2 << 5) /* Word length: 7 bits */
+#define UART_LCR_H_WLEN8 (0x3 << 5) /* Word length: 8 bits */
+#define UART_LCR_H_SPS (1 << 7) /* Stick parity select */
+#define UART_CR 0x30 /* Control register */
+#define UART_CR_UARTEN (1 << 0) /* UART enable */
+#define UART_CR_SIREN (1 << 1) /* SIR enable */
+#define UART_CR_SIRLP (1 << 2) /* IrDA SIR low power mode */
+#define UART_CR_LBE (1 << 7) /* Loop back enable */
+#define UART_CR_TXE (1 << 8) /* Transmit enable */
+#define UART_CR_RXE (1 << 9) /* Receive enable */
+#define UART_CR_DTR (1 << 10) /* Data transmit enable */
+#define UART_CR_RTS (1 << 11) /* Request to send */
+#define UART_CR_OUT1 (1 << 12)
+#define UART_CR_OUT2 (1 << 13)
+#define UART_CR_CTSE (1 << 14) /* CTS hardware flow control enable */
+#define UART_CR_RTSE (1 << 15) /* RTS hardware flow control enable */
+#define UART_IFLS 0x34 /* Interrupt FIFO level select register */
+#define UART_IMSC 0x38 /* Interrupt mask set/clear register */
+#define UART_IMSC_RIMIM (1 << 0)
+#define UART_IMSC_CTSMIM (1 << 1)
+#define UART_IMSC_DCDMIM (1 << 2)
+#define UART_IMSC_DSRMIM (1 << 3)
+#define UART_IMSC_RXIM (1 << 4)
+#define UART_IMSC_TXIM (1 << 5)
+#define UART_IMSC_RTIM (1 << 6)
+#define UART_IMSC_FEIM (1 << 7)
+#define UART_IMSC_PEIM (1 << 8)
+#define UART_IMSC_BEIM (1 << 9)
+#define UART_IMSC_OEIM (1 << 10)
+#define UART_RIS 0x3c /* Raw interrupt status register */
+#define UART_MIS 0x40 /* Masked interrupt status register */
+#define UART_ICR 0x44 /* Interrupt clear register */
+#define UART_DMACR 0x48 /* DMA control register */
+#define UART_SPACE 0x100
+
+struct pluart_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ struct soft_intrhand *sc_si;
+ void *sc_irq;
+ struct tty *sc_tty;
+ struct timeout sc_diag_tmo;
+ struct timeout sc_dtr_tmo;
+ int sc_overflows;
+ int sc_floods;
+ int sc_errors;
+ int sc_halt;
+ u_int16_t sc_ucr1;
+ u_int16_t sc_ucr2;
+ u_int16_t sc_ucr3;
+ u_int16_t sc_ucr4;
+ u_int8_t sc_hwflags;
+#define COM_HW_NOIEN 0x01
+#define COM_HW_FIFO 0x02
+#define COM_HW_SIR 0x20
+#define COM_HW_CONSOLE 0x40
+#define COM_HW_KGDB 0x80
+ u_int8_t sc_swflags;
+#define COM_SW_SOFTCAR 0x01
+#define COM_SW_CLOCAL 0x02
+#define COM_SW_CRTSCTS 0x04
+#define COM_SW_MDMBUF 0x08
+#define COM_SW_PPS 0x10
+ int sc_fifolen;
+
+ u_int8_t sc_initialize;
+ u_int8_t sc_cua;
+ u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+#define UART_IBUFSIZE 128
+#define UART_IHIGHWATER 100
+ u_int16_t sc_ibufs[2][UART_IBUFSIZE];
+
+ struct clk *sc_clk;
+};
+
+int pluartprobe(struct device *parent, void *self, void *aux);
+void pluartattach(struct device *parent, struct device *self, void *aux);
+
+void pluartcnprobe(struct consdev *cp);
+void pluartcnprobe(struct consdev *cp);
+void pluartcninit(struct consdev *cp);
+int pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
+ tcflag_t cflag);
+int pluartcngetc(dev_t dev);
+void pluartcnputc(dev_t dev, int c);
+void pluartcnpollc(dev_t dev, int on);
+int pluart_param(struct tty *tp, struct termios *t);
+void pluart_start(struct tty *);
+void pluart_pwroff(struct pluart_softc *sc);
+void pluart_diag(void *arg);
+void pluart_raisedtr(void *arg);
+void pluart_softint(void *arg);
+struct pluart_softc *pluart_sc(dev_t dev);
+
+int pluart_intr(void *);
+
+extern int comcnspeed;
+extern int comcnmode;
+
+/* XXX - we imitate 'com' serial ports and take over their entry points */
+/* XXX: These belong elsewhere */
+cdev_decl(pluart);
+
+struct cfdriver pluart_cd = {
+ NULL, "pluart", DV_TTY
+};
+
+struct cfattach pluart_ca = {
+ sizeof(struct pluart_softc), pluartprobe, pluartattach
+};
+
+bus_space_tag_t pluartconsiot;
+bus_space_handle_t pluartconsioh;
+bus_addr_t pluartconsaddr;
+tcflag_t pluartconscflag = TTYDEF_CFLAG;
+int pluartdefaultrate = B38400;
+
+void
+pluart_init_cons(void)
+{
+ struct fdt_reg reg;
+ void *node;
+
+ if ((node = fdt_find_cons("arm,pl011")) == NULL)
+ return;
+ if (fdt_get_reg(node, 0, &reg))
+ return;
+
+ pluartcnattach(&arm64_bs_tag, reg.addr, comcnspeed, comcnmode);
+}
+
+int
+pluartprobe(struct device *parent, void *self, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "arm,pl011");
+}
+
+struct cdevsw pluartdev =
+ cdev_tty_init(3/*XXX NUART */ ,pluart); /* 8: serial port */
+
+void
+pluartattach(struct device *parent, struct device *self, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+ struct pluart_softc *sc = (struct pluart_softc *) self;
+ int maj;
+
+ if (faa->fa_nreg < 1) {
+ printf(": no register data\n");
+ return;
+ }
+
+ sc->sc_irq = arm_intr_establish_fdt(faa->fa_node, IPL_TTY, pluart_intr,
+ sc, sc->sc_dev.dv_xname);
+
+ sc->sc_iot = faa->fa_iot;
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
+ 0, &sc->sc_ioh))
+ panic("pluartattach: bus_space_map failed!");
+
+ if (stdout_node == faa->fa_node) {
+ /* Locate the major number. */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == pluartopen)
+ break;
+ cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
+
+ printf(": console");
+ }
+
+ timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
+ timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
+ sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
+
+ if(sc->sc_si == NULL)
+ panic("%s: can't establish soft interrupt.",
+ sc->sc_dev.dv_xname);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) &
+ ~UART_LCR_H_FEN);
+
+ printf("\n");
+}
+
+int
+pluart_intr(void *arg)
+{
+ struct pluart_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct tty *tp = sc->sc_tty;
+ u_int16_t fr;
+ u_int16_t *p;
+ u_int16_t c;
+
+ bus_space_write_4(iot, ioh, UART_ICR, -1);
+
+ if (sc->sc_tty == NULL)
+ return(0);
+
+ fr = bus_space_read_4(iot, ioh, UART_FR);
+ if (ISSET(fr, UART_FR_TXFE) && ISSET(tp->t_state, TS_BUSY)) {
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+ if (sc->sc_halt > 0)
+ wakeup(&tp->t_outq);
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+
+ if(!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF))
+ return 0;
+
+ p = sc->sc_ibufp;
+
+ while(ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) {
+ c = bus_space_read_1(iot, ioh, UART_DR);
+ if (p >= sc->sc_ibufend) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout_add(&sc->sc_diag_tmo, 60 * hz);
+ } else {
+ *p++ = c;
+ if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) {
+ /* XXX */
+ //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
+ //bus_space_write_4(iot, ioh, IMXUART_UCR3,
+ // sc->sc_ucr3);
+ }
+ }
+ /* XXX - msr stuff ? */
+ }
+ sc->sc_ibufp = p;
+
+ softintr_schedule(sc->sc_si);
+
+ return 1;
+}
+
+int
+pluart_param(struct tty *tp, struct termios *t)
+{
+ struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ //bus_space_tag_t iot = sc->sc_iot;
+ //bus_space_handle_t ioh = sc->sc_ioh;
+ int ospeed = t->c_ospeed;
+ int error;
+ tcflag_t oldcflag;
+
+
+ if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+ return EINVAL;
+
+ switch (ISSET(t->c_cflag, CSIZE)) {
+ case CS5:
+ return EINVAL;
+ case CS6:
+ return EINVAL;
+ case CS7:
+ //CLR(sc->sc_ucr2, IMXUART_CR2_WS);
+ break;
+ case CS8:
+ //SET(sc->sc_ucr2, IMXUART_CR2_WS);
+ break;
+ }
+// bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
+
+ /*
+ if (ISSET(t->c_cflag, PARENB)) {
+ SET(sc->sc_ucr2, IMXUART_CR2_PREN);
+ bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
+ }
+ */
+ /* STOPB - XXX */
+ if (ospeed == 0) {
+ /* lower dtr */
+ }
+
+ if (ospeed != 0) {
+ while (ISSET(tp->t_state, TS_BUSY)) {
+ ++sc->sc_halt;
+ error = ttysleep(tp, &tp->t_outq,
+ TTOPRI | PCATCH, "pluartprm", 0);
+ --sc->sc_halt;
+ if (error) {
+ pluart_start(tp);
+ return (error);
+ }
+ }
+ /* set speed */
+ }
+
+ /* setup fifo */
+
+ /* When not using CRTSCTS, RTS follows DTR. */
+ /* sc->sc_dtr = MCR_DTR; */
+
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ oldcflag = tp->t_cflag;
+ tp->t_cflag = t->c_cflag;
+
+ /*
+ * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+ * stop the device.
+ */
+ /* XXX */
+
+ pluart_start(tp);
+
+ return 0;
+}
+
+void
+pluart_start(struct tty *tp)
+{
+ struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ int s;
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (ISSET(tp->t_state, TS_ASLEEP)) {
+ CLR(tp->t_state, TS_ASLEEP);
+ wakeup(&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+ selwakeup(&tp->t_wsel);
+ }
+ SET(tp->t_state, TS_BUSY);
+
+ if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) {
+ u_char buffer[64]; /* largest fifo */
+ int i, n;
+
+ n = q_to_b(&tp->t_outq, buffer,
+ min(sc->sc_fifolen, sizeof buffer));
+ for (i = 0; i < n; i++) {
+ bus_space_write_4(iot, ioh, UART_DR, buffer[i]);
+ }
+ bzero(buffer, n);
+ } else if (tp->t_outq.c_cc != 0)
+ bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
+
+out:
+ splx(s);
+}
+
+void
+pluart_pwroff(struct pluart_softc *sc)
+{
+}
+
+void
+pluart_diag(void *arg)
+{
+ struct pluart_softc *sc = arg;
+ int overflows, floods;
+ int s;
+
+ s = spltty();
+ sc->sc_errors = 0;
+ overflows = sc->sc_overflows;
+ sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ splx(s);
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+pluart_raisedtr(void *arg)
+{
+ //struct pluart_softc *sc = arg;
+
+ //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
+ //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
+}
+
+void
+pluart_softint(void *arg)
+{
+ struct pluart_softc *sc = arg;
+ struct tty *tp;
+ u_int16_t *ibufp;
+ u_int16_t *ibufend;
+ int c;
+ int err;
+ int s;
+
+ if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
+ return;
+
+ tp = sc->sc_tty;
+ s = spltty();
+
+ ibufp = sc->sc_ibuf;
+ ibufend = sc->sc_ibufp;
+
+ if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
+ splx(s);
+ return;
+ }
+
+ sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+ sc->sc_ibufs[1] : sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
+
+#if 0
+ if (ISSET(tp->t_cflag, CRTSCTS) &&
+ !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
+ /* XXX */
+ SET(sc->sc_ucr3, IMXUART_CR3_DSR);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
+ sc->sc_ucr3);
+ }
+#endif
+
+ splx(s);
+
+ while (ibufp < ibufend) {
+ c = *ibufp++;
+ /*
+ if (ISSET(c, IMXUART_RX_OVERRUN)) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout_add(&sc->sc_diag_tmo, 60 * hz);
+ }
+ */
+ /* This is ugly, but fast. */
+
+ err = 0;
+ /*
+ if (ISSET(c, IMXUART_RX_PRERR))
+ err |= TTY_PE;
+ if (ISSET(c, IMXUART_RX_FRMERR))
+ err |= TTY_FE;
+ */
+ c = (c & 0xff) | err;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+}
+
+int
+pluartopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ int unit = DEVUNIT(dev);
+ struct pluart_softc *sc;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct tty *tp;
+ int s;
+ int error = 0;
+
+ if (unit >= pluart_cd.cd_ndevs)
+ return ENXIO;
+ sc = pluart_cd.cd_devs[unit];
+ if (sc == NULL)
+ return ENXIO;
+
+ s = spltty();
+ if (sc->sc_tty == NULL)
+ tp = sc->sc_tty = ttymalloc(0);
+ else
+ tp = sc->sc_tty;
+
+ splx(s);
+
+ tp->t_oproc = pluart_start;
+ tp->t_param = pluart_param;
+ tp->t_dev = dev;
+
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ SET(tp->t_state, TS_WOPEN);
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ tp->t_cflag = pluartconscflag;
+ else
+ tp->t_cflag = TTYDEF_CFLAG;
+ if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
+ SET(tp->t_cflag, CLOCAL);
+ if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
+ SET(tp->t_cflag, CRTSCTS);
+ if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
+ SET(tp->t_cflag, MDMBUF);
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
+
+ s = spltty();
+
+ sc->sc_initialize = 1;
+ pluart_param(tp, &tp->t_termios);
+ ttsetwater(tp);
+ sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
+
+ iot = sc->sc_iot;
+ ioh = sc->sc_ioh;
+
+#if 0
+ sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
+ sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
+ sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
+ sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
+
+ /* interrupt after one char on tx/rx */
+ /* reference frequency divider: 1 */
+ bus_space_write_4(iot, ioh, IMXUART_UFCR,
+ 1 << IMXUART_FCR_TXTL_SH |
+ 5 << IMXUART_FCR_RFDIV_SH |
+ 1 << IMXUART_FCR_RXTL_SH);
+
+ bus_space_write_4(iot, ioh, IMXUART_UBIR,
+ (pluartdefaultrate / 100) - 1);
+
+ /* formula: clk / (rfdiv * 1600) */
+ bus_space_write_4(iot, ioh, IMXUART_UBMR,
+ (clk_get_rate(sc->sc_clk) * 1000) / 1600);
+
+ SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
+ SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
+ bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
+ bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
+
+ /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
+ SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
+ bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
+#endif
+
+ SET(tp->t_state, TS_CARR_ON); /* XXX */
+
+
+ } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+ else
+ s = spltty();
+
+ if (DEVCUA(dev)) {
+ if (ISSET(tp->t_state, TS_ISOPEN)) {
+ splx(s);
+ return EBUSY;
+ }
+ sc->sc_cua = 1;
+ } else {
+ /* tty (not cua) device; wait for carrier if necessary */
+ if (ISSET(flag, O_NONBLOCK)) {
+ if (sc->sc_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy */
+ splx(s);
+ return EBUSY;
+ }
+ } else {
+ while (sc->sc_cua ||
+ (!ISSET(tp->t_cflag, CLOCAL) &&
+ !ISSET(tp->t_state, TS_CARR_ON))) {
+ SET(tp->t_state, TS_WOPEN);
+ error = ttysleep(tp, &tp->t_rawq,
+ TTIPRI | PCATCH, ttopen, 0);
+ /*
+ * If TS_WOPEN has been reset, that means the
+ * cua device has been closed. We don't want
+ * to fail in that case,
+ * so just go around again.
+ */
+ if (error && ISSET(tp->t_state, TS_WOPEN)) {
+ CLR(tp->t_state, TS_WOPEN);
+ if (!sc->sc_cua && !ISSET(tp->t_state,
+ TS_ISOPEN))
+ pluart_pwroff(sc);
+ splx(s);
+ return error;
+ }
+ }
+ }
+ }
+ splx(s);
+ return (*linesw[tp->t_line].l_open)(dev,tp,p);
+}
+
+int
+pluartclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ int unit = DEVUNIT(dev);
+ struct pluart_softc *sc = pluart_cd.cd_devs[unit];
+ //bus_space_tag_t iot = sc->sc_iot;
+ //bus_space_handle_t ioh = sc->sc_ioh;
+ struct tty *tp = sc->sc_tty;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flag, p);
+ s = spltty();
+ if (ISSET(tp->t_state, TS_WOPEN)) {
+ /* tty device is waiting for carrier; drop dtr then re-raise */
+ //CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
+ //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
+ timeout_add(&sc->sc_dtr_tmo, hz * 2);
+ } else {
+ /* no one else waiting; turn off the uart */
+ pluart_pwroff(sc);
+ }
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+
+ sc->sc_cua = 0;
+ splx(s);
+ ttyclose(tp);
+
+ return 0;
+}
+
+int
+pluartread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tty;
+
+ tty = pluarttty(dev);
+ if (tty == NULL)
+ return ENODEV;
+
+ return((*linesw[tty->t_line].l_read)(tty, uio, flag));
+}
+
+int
+pluartwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tty;
+
+ tty = pluarttty(dev);
+ if (tty == NULL)
+ return ENODEV;
+
+ return((*linesw[tty->t_line].l_write)(tty, uio, flag));
+}
+
+int
+pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct pluart_softc *sc;
+ struct tty *tp;
+ int error;
+
+ sc = pluart_sc(dev);
+ if (sc == NULL)
+ return (ENODEV);
+
+ tp = sc->sc_tty;
+ if (tp == NULL)
+ return (ENXIO);
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ switch(cmd) {
+ case TIOCSBRK:
+ break;
+ case TIOCCBRK:
+ break;
+ case TIOCSDTR:
+ break;
+ case TIOCCDTR:
+ break;
+ case TIOCMSET:
+ break;
+ case TIOCMBIS:
+ break;
+ case TIOCMBIC:
+ break;
+ case TIOCMGET:
+ break;
+ case TIOCGFLAGS:
+ break;
+ case TIOCSFLAGS:
+ error = suser(p, 0);
+ if (error != 0)
+ return(EPERM);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return 0;
+}
+
+int
+pluartstop(struct tty *tp, int flag)
+{
+ return 0;
+}
+
+struct tty *
+pluarttty(dev_t dev)
+{
+ int unit;
+ struct pluart_softc *sc;
+ unit = DEVUNIT(dev);
+ if (unit >= pluart_cd.cd_ndevs)
+ return NULL;
+ sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
+ if (sc == NULL)
+ return NULL;
+ return sc->sc_tty;
+}
+
+struct pluart_softc *
+pluart_sc(dev_t dev)
+{
+ int unit;
+ struct pluart_softc *sc;
+ unit = DEVUNIT(dev);
+ if (unit >= pluart_cd.cd_ndevs)
+ return NULL;
+ sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
+ return sc;
+}
+
+
+/* serial console */
+void
+pluartcnprobe(struct consdev *cp)
+{
+ cp->cn_dev = makedev(8 /* XXX */, 0);
+ cp->cn_pri = CN_MIDPRI;
+}
+
+void
+pluartcninit(struct consdev *cp)
+{
+}
+
+int
+pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
+{
+ static struct consdev pluartcons = {
+ NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
+ NODEV, CN_MIDPRI
+ };
+
+ if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
+ return ENOMEM;
+
+ /* Disable FIFO. */
+ bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
+ bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
+
+ cn_tab = &pluartcons;
+ cn_tab->cn_dev = makedev(8 /* XXX */, 0);
+ cdevsw[8] = pluartdev; /* KLUDGE */
+
+ pluartconsiot = iot;
+ pluartconsaddr = iobase;
+ pluartconscflag = cflag;
+
+ return 0;
+}
+
+int
+pluartcngetc(dev_t dev)
+{
+ int c;
+ int s;
+ s = splhigh();
+ while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
+ UART_FR_RXFF) == 0)
+ ;
+ c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
+ splx(s);
+ return c;
+}
+
+void
+pluartcnputc(dev_t dev, int c)
+{
+ int s;
+ s = splhigh();
+ while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
+ UART_FR_TXFE) == 0)
+ ;
+ bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
+ splx(s);
+}
+
+void
+pluartcnpollc(dev_t dev, int on)
+{
+}
diff --git a/sys/arch/arm64/dev/simplebus.c b/sys/arch/arm64/dev/simplebus.c
new file mode 100644
index 00000000000..ec3a07d10da
--- /dev/null
+++ b/sys/arch/arm64/dev/simplebus.c
@@ -0,0 +1,242 @@
+/* $OpenBSD: simplebus.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#include <arm64/fdt.h>
+#include <arm64/dev/simplebusvar.h>
+
+int simplebus_match(struct device *, void *, void *);
+void simplebus_attach(struct device *, struct device *, void *);
+
+void simplebus_attach_node(struct device *, int);
+int simplebus_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *);
+
+struct cfattach simplebus_ca = {
+ sizeof(struct simplebus_softc), simplebus_match, simplebus_attach, NULL,
+ config_activate_children
+};
+
+struct cfdriver simplebus_cd = {
+ NULL, "simplebus", DV_DULL
+};
+
+/*
+ * Simplebus is a generic bus with no special casings.
+ */
+int
+simplebus_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
+
+ if (fa->fa_node == 0)
+ return (0);
+
+ if (!OF_is_compatible(fa->fa_node, "simple-bus"))
+ return (0);
+
+ return (1);
+}
+
+void
+simplebus_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct simplebus_softc *sc = (struct simplebus_softc *)self;
+ struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
+ char name[32];
+ int node;
+
+ sc->sc_node = fa->fa_node;
+ sc->sc_iot = fa->fa_iot;
+ sc->sc_dmat = fa->fa_dmat;
+ sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
+ fa->fa_acells);
+ sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
+ fa->fa_scells);
+ sc->sc_pacells = fa->fa_acells;
+ sc->sc_pscells = fa->fa_scells;
+
+ if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
+ name[sizeof(name) - 1] = 0;
+ printf(": \"%s\"", name);
+ }
+
+ printf("\n");
+
+ memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus));
+ sc->sc_bus.bus_private = sc;
+ sc->sc_bus._space_map = simplebus_bs_map;
+
+ sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges");
+ if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) {
+ sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges,
+ sc->sc_rangeslen);
+ }
+
+ /* Scan the whole tree. */
+ sc->sc_early = 1;
+ for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
+ simplebus_attach_node(self, node);
+
+ sc->sc_early = 0;
+ for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
+ simplebus_attach_node(self, node);
+}
+
+int
+simplebus_submatch(struct device *self, void *match, void *aux)
+{
+ struct simplebus_softc *sc = (struct simplebus_softc *)self;
+ struct cfdata *cf = match;
+
+ if (cf->cf_loc[0] == sc->sc_early)
+ return (*cf->cf_attach->ca_match)(self, match, aux);
+ return 0;
+}
+
+/*
+ * Look for a driver that wants to be attached to this node.
+ */
+void
+simplebus_attach_node(struct device *self, int node)
+{
+ struct simplebus_softc *sc = (struct simplebus_softc *)self;
+ struct fdt_attach_args fa;
+ char buffer[128];
+ int i, len, line;
+ uint32_t *cell, *reg;
+
+ if (!OF_getprop(node, "compatible", buffer, sizeof(buffer)))
+ return;
+
+ if (OF_getprop(node, "status", buffer, sizeof(buffer)))
+ if (!strcmp(buffer, "disabled"))
+ return;
+
+ memset(&fa, 0, sizeof(fa));
+ fa.fa_name = "";
+ fa.fa_node = node;
+ fa.fa_iot = &sc->sc_bus;
+ fa.fa_dmat = sc->sc_dmat;
+ fa.fa_acells = sc->sc_acells;
+ fa.fa_scells = sc->sc_scells;
+
+ len = OF_getproplen(node, "reg");
+ line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
+ if (len > 0 && line > 0 && (len % line) == 0) {
+ reg = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "reg", reg, len);
+
+ fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+ fa.fa_nreg = (len / line);
+
+ for (i = 0, cell = reg; i < len / line; i++) {
+ if (sc->sc_acells >= 1)
+ fa.fa_reg[i].addr = cell[0];
+ if (sc->sc_acells == 2) {
+ fa.fa_reg[i].addr <<= 32;
+ fa.fa_reg[i].addr |= cell[1];
+ }
+ cell += sc->sc_acells;
+ if (sc->sc_scells >= 1)
+ fa.fa_reg[i].size = cell[0];
+ if (sc->sc_scells == 2) {
+ fa.fa_reg[i].size <<= 32;
+ fa.fa_reg[i].size |= cell[1];
+ }
+ cell += sc->sc_scells;
+ }
+
+ free(reg, M_TEMP, len);
+ }
+
+ len = OF_getproplen(node, "interrupts");
+ if (len > 0 && (len % sizeof(uint32_t)) == 0) {
+ fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
+ fa.fa_nintr = len / sizeof(uint32_t);
+
+ OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
+ }
+
+ config_found_sm(self, &fa, NULL, simplebus_submatch);
+
+ free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
+ free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
+}
+
+/*
+ * Translate memory address if needed.
+ */
+int
+simplebus_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
+ int flag, bus_space_handle_t *bshp)
+{
+ struct simplebus_softc *sc = (struct simplebus_softc *)t;
+ uint64_t addr, rfrom, rto, rsize;
+ uint32_t *range;
+ int parent, rlen, rone;
+
+ addr = bpa;
+ parent = OF_parent(sc->sc_node);
+ if (parent == 0)
+ return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
+
+ if (sc->sc_rangeslen < 0)
+ return EINVAL;
+ if (sc->sc_rangeslen == 0)
+ return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
+
+ rlen = sc->sc_rangeslen / sizeof(uint32_t);
+ rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
+
+ /* For each range. */
+ for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) {
+ /* Extract from and size, so we can see if we fit. */
+ rfrom = range[0];
+ if (sc->sc_acells == 2)
+ rfrom = (rfrom << 32) + range[1];
+ rsize = range[sc->sc_acells + sc->sc_pacells];
+ if (sc->sc_scells == 2)
+ rsize = (rsize << 32) +
+ range[sc->sc_acells + sc->sc_pacells + 1];
+
+ /* Try next, if we're not in the range. */
+ if (addr < rfrom || (addr + size) > (rfrom + rsize))
+ continue;
+
+ /* All good, extract to address and translate. */
+ rto = range[sc->sc_acells];
+ if (sc->sc_pacells == 2)
+ rto = (rto << 32) + range[sc->sc_acells + 1];
+
+ addr -= rfrom;
+ addr += rto;
+
+ return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
+ }
+
+ return ESRCH;
+}
diff --git a/sys/arch/arm64/dev/simplebusvar.h b/sys/arch/arm64/dev/simplebusvar.h
new file mode 100644
index 00000000000..4bde6e92bd5
--- /dev/null
+++ b/sys/arch/arm64/dev/simplebusvar.h
@@ -0,0 +1,33 @@
+/* $OpenBSD: simplebusvar.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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.
+ */
+
+struct simplebus_softc {
+ struct device sc_dev;
+ int sc_node;
+ bus_space_tag_t sc_iot;
+ bus_dma_tag_t sc_dmat;
+ int sc_acells;
+ int sc_scells;
+ int sc_pacells;
+ int sc_pscells;
+ struct bus_space sc_bus;
+ int *sc_ranges;
+ int sc_rangeslen;
+ int sc_early;
+};
+
+extern void simplebus_attach(struct device *, struct device *, void *);
diff --git a/sys/arch/arm64/dev/virtio_mmio.c b/sys/arch/arm64/dev/virtio_mmio.c
new file mode 100644
index 00000000000..091f2e6c8d6
--- /dev/null
+++ b/sys/arch/arm64/dev/virtio_mmio.c
@@ -0,0 +1,454 @@
+/* $OpenBSD: virtio_mmio.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $ */
+
+/*
+ * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
+ * Copyright (c) 2012 Stefan Fritsch.
+ * Copyright (c) 2010 Minoura Makoto.
+ * 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 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/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+
+#include <dev/pci/virtioreg.h>
+#include <dev/pci/virtiovar.h>
+
+#include <machine/fdt.h>
+#include <arm64/arm64/arm64var.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
+#define VIRTIO_MMIO_MAGIC ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)
+
+#define VIRTIO_MMIO_MAGIC_VALUE 0x000
+#define VIRTIO_MMIO_VERSION 0x004
+#define VIRTIO_MMIO_DEVICE_ID 0x008
+#define VIRTIO_MMIO_VENDOR_ID 0x00c
+#define VIRTIO_MMIO_HOST_FEATURES 0x010
+#define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014
+#define VIRTIO_MMIO_GUEST_FEATURES 0x020
+#define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024
+#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028
+#define VIRTIO_MMIO_QUEUE_SEL 0x030
+#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034
+#define VIRTIO_MMIO_QUEUE_NUM 0x038
+#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c
+#define VIRTIO_MMIO_QUEUE_PFN 0x040
+#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050
+#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060
+#define VIRTIO_MMIO_INTERRUPT_ACK 0x064
+#define VIRTIO_MMIO_STATUS 0x070
+#define VIRTIO_MMIO_CONFIG 0x100
+
+#define VIRTIO_MMIO_INT_VRING (1 << 0)
+#define VIRTIO_MMIO_INT_CONFIG (1 << 1)
+
+#define DEVNAME(sc) (sc)->sc_dev.dv_xname
+
+/*
+ * XXX: Before being used on big endian arches, the access to config registers
+ * XXX: needs to be reviewed/fixed. The non-device specific registers are
+ * XXX: PCI-endian while the device specific registers are native endian.
+ */
+
+#define virtio_set_status(sc, s) virtio_mmio_set_status(sc, s)
+#define virtio_device_reset(sc) virtio_set_status((sc), 0)
+
+int virtio_mmio_match(struct device *, void *, void *);
+void virtio_mmio_attach(struct device *, struct device *, void *);
+int virtio_mmio_detach(struct device *, int);
+
+void virtio_mmio_kick(struct virtio_softc *, uint16_t);
+uint8_t virtio_mmio_read_device_config_1(struct virtio_softc *, int);
+uint16_t virtio_mmio_read_device_config_2(struct virtio_softc *, int);
+uint32_t virtio_mmio_read_device_config_4(struct virtio_softc *, int);
+uint64_t virtio_mmio_read_device_config_8(struct virtio_softc *, int);
+void virtio_mmio_write_device_config_1(struct virtio_softc *, int, uint8_t);
+void virtio_mmio_write_device_config_2(struct virtio_softc *, int, uint16_t);
+void virtio_mmio_write_device_config_4(struct virtio_softc *, int, uint32_t);
+void virtio_mmio_write_device_config_8(struct virtio_softc *, int, uint64_t);
+uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t);
+void virtio_mmio_setup_queue(struct virtio_softc *, uint16_t, uint32_t);
+void virtio_mmio_set_status(struct virtio_softc *, int);
+uint32_t virtio_mmio_negotiate_features(struct virtio_softc *, uint32_t,
+ const struct virtio_feature_name *);
+int virtio_mmio_intr(void *);
+
+struct virtio_mmio_softc {
+ struct virtio_softc sc_sc;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_size_t sc_iosize;
+ bus_dma_tag_t sc_dmat;
+
+ void *sc_ih;
+
+ int sc_config_offset;
+};
+
+struct cfattach virtio_mmio_ca = {
+ sizeof(struct virtio_mmio_softc),
+ virtio_mmio_match,
+ virtio_mmio_attach,
+ virtio_mmio_detach,
+ NULL
+};
+
+struct cfattach virtio_mmio_fdt_ca = {
+ sizeof(struct virtio_mmio_softc),
+ NULL,
+ virtio_mmio_attach,
+ virtio_mmio_detach,
+ NULL
+};
+
+struct virtio_ops virtio_mmio_ops = {
+ virtio_mmio_kick,
+ virtio_mmio_read_device_config_1,
+ virtio_mmio_read_device_config_2,
+ virtio_mmio_read_device_config_4,
+ virtio_mmio_read_device_config_8,
+ virtio_mmio_write_device_config_1,
+ virtio_mmio_write_device_config_2,
+ virtio_mmio_write_device_config_4,
+ virtio_mmio_write_device_config_8,
+ virtio_mmio_read_queue_size,
+ virtio_mmio_setup_queue,
+ virtio_mmio_set_status,
+ virtio_mmio_negotiate_features,
+ virtio_mmio_intr,
+};
+
+uint16_t
+virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx);
+ return bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_QUEUE_NUM_MAX);
+}
+
+void
+virtio_mmio_setup_queue(struct virtio_softc *vsc, uint16_t idx, uint32_t addr)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NUM,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NUM_MAX));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_ALIGN,
+ PAGE_SIZE);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_PFN, addr);
+}
+
+void
+virtio_mmio_set_status(struct virtio_softc *vsc, int status)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ int old = 0;
+
+ if (status != 0)
+ old = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_STATUS);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_STATUS,
+ status|old);
+}
+
+int
+virtio_mmio_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "virtio,mmio");
+}
+
+void
+virtio_mmio_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)self;
+ struct virtio_softc *vsc = &sc->sc_sc;
+ uint32_t id, magic, version;
+
+ if (faa->fa_nreg < 1) {
+ printf(": no register data\n");
+ return;
+ }
+
+ sc->sc_iosize = faa->fa_reg[0].size;
+ sc->sc_iot = faa->fa_iot;
+ sc->sc_dmat = faa->fa_dmat;
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
+ 0, &sc->sc_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_MAGIC_VALUE);
+ if (magic != VIRTIO_MMIO_MAGIC) {
+ printf(": wrong magic value 0x%08x; giving up\n", magic);
+ return;
+ }
+
+ version = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_VERSION);
+ if (version != 1) {
+ printf(": unknown version 0x%02x; giving up\n", version);
+ return;
+ }
+
+ id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_DEVICE_ID);
+ printf(": Virtio %s Device", virtio_device_string(id));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_GUEST_PAGE_SIZE,
+ PAGE_SIZE);
+
+ printf("\n");
+
+ /* No device connected. */
+ if (id == 0)
+ return;
+
+ vsc->sc_ops = &virtio_mmio_ops;
+ vsc->sc_dmat = sc->sc_dmat;
+ sc->sc_config_offset = VIRTIO_MMIO_CONFIG;
+
+ virtio_device_reset(vsc);
+ virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
+ virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);
+
+ /* XXX: use softc as aux... */
+ vsc->sc_childdevid = id;
+ vsc->sc_child = NULL;
+ config_found(self, sc, NULL);
+ if (vsc->sc_child == NULL) {
+ printf("%s: no matching child driver; not configured\n",
+ vsc->sc_dev.dv_xname);
+ goto fail_1;
+ }
+ if (vsc->sc_child == VIRTIO_CHILD_ERROR) {
+ printf("%s: virtio configuration failed\n",
+ vsc->sc_dev.dv_xname);
+ goto fail_1;
+ }
+
+ sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, vsc->sc_ipl,
+ virtio_mmio_intr, sc, vsc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt\n",
+ vsc->sc_dev.dv_xname);
+ goto fail_2;
+ }
+
+ virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK);
+ return;
+
+fail_2:
+ config_detach(vsc->sc_child, 0);
+fail_1:
+ /* no mmio_mapreg_unmap() or mmio_intr_unmap() */
+ virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
+}
+
+int
+virtio_mmio_detach(struct device *self, int flags)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)self;
+ struct virtio_softc *vsc = &sc->sc_sc;
+ int r;
+
+ if (vsc->sc_child != 0 && vsc->sc_child != VIRTIO_CHILD_ERROR) {
+ r = config_detach(vsc->sc_child, flags);
+ if (r)
+ return r;
+ }
+ KASSERT(vsc->sc_child == 0 || vsc->sc_child == VIRTIO_CHILD_ERROR);
+ KASSERT(vsc->sc_vqs == 0);
+ arm_intr_disestablish(sc->sc_ih);
+ sc->sc_ih = 0;
+ if (sc->sc_iosize)
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+ sc->sc_iosize = 0;
+
+ return 0;
+}
+
+/*
+ * Feature negotiation.
+ * Prints available / negotiated features if guest_feature_names != NULL and
+ * VIRTIO_DEBUG is 1
+ */
+uint32_t
+virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint32_t guest_features,
+ const struct virtio_feature_name *guest_feature_names)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ uint32_t host, neg;
+
+ /*
+ * indirect descriptors can be switched off by setting bit 1 in the
+ * driver flags, see config(8)
+ */
+ if (!(vsc->sc_dev.dv_cfdata->cf_flags & 1) &&
+ !(vsc->sc_child->dv_cfdata->cf_flags & 1)) {
+ guest_features |= VIRTIO_F_RING_INDIRECT_DESC;
+ } else {
+ printf("RingIndirectDesc disabled by UKC\n");
+ }
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_HOST_FEATURES_SEL, 0);
+ host = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_HOST_FEATURES);
+ neg = host & guest_features;
+#if VIRTIO_DEBUG
+ if (guest_feature_names)
+ virtio_log_features(host, neg, guest_feature_names);
+#endif
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_GUEST_FEATURES_SEL, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_GUEST_FEATURES, neg);
+ vsc->sc_features = neg;
+ if (neg & VIRTIO_F_RING_INDIRECT_DESC)
+ vsc->sc_indirect = 1;
+ else
+ vsc->sc_indirect = 0;
+
+ return neg;
+}
+
+/*
+ * Device configuration registers.
+ */
+uint8_t
+virtio_mmio_read_device_config_1(struct virtio_softc *vsc, int index)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ return bus_space_read_1(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index);
+}
+
+uint16_t
+virtio_mmio_read_device_config_2(struct virtio_softc *vsc, int index)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index);
+}
+
+uint32_t
+virtio_mmio_read_device_config_4(struct virtio_softc *vsc, int index)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ return bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index);
+}
+
+uint64_t
+virtio_mmio_read_device_config_8(struct virtio_softc *vsc, int index)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ uint64_t r;
+
+ r = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index + sizeof(uint32_t));
+ r <<= 32;
+ r += bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index);
+ return r;
+}
+
+void
+virtio_mmio_write_device_config_1(struct virtio_softc *vsc,
+ int index, uint8_t value)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index, value);
+}
+
+void
+virtio_mmio_write_device_config_2(struct virtio_softc *vsc,
+ int index, uint16_t value)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index, value);
+}
+
+void
+virtio_mmio_write_device_config_4(struct virtio_softc *vsc,
+ int index, uint32_t value)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index, value);
+}
+
+void
+virtio_mmio_write_device_config_8(struct virtio_softc *vsc,
+ int index, uint64_t value)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index,
+ value & 0xffffffff);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ sc->sc_config_offset + index + sizeof(uint32_t),
+ value >> 32);
+}
+
+/*
+ * Interrupt handler.
+ */
+int
+virtio_mmio_intr(void *arg)
+{
+ struct virtio_mmio_softc *sc = arg;
+ struct virtio_softc *vsc = &sc->sc_sc;
+ int isr, r = 0;
+
+ /* check and ack the interrupt */
+ isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_INTERRUPT_STATUS);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ VIRTIO_MMIO_INTERRUPT_ACK, isr);
+ if ((isr & VIRTIO_MMIO_INT_CONFIG) &&
+ (vsc->sc_config_change != NULL))
+ r = (vsc->sc_config_change)(vsc);
+ if ((isr & VIRTIO_MMIO_INT_VRING))
+ r |= virtio_check_vqs(vsc);
+
+ return r;
+}
+
+void
+virtio_mmio_kick(struct virtio_softc *vsc, uint16_t idx)
+{
+ struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NOTIFY,
+ idx);
+}
diff --git a/sys/arch/arm64/include/_float.h b/sys/arch/arm64/include/_float.h
new file mode 100644
index 00000000000..db4509cf4ad
--- /dev/null
+++ b/sys/arch/arm64/include/_float.h
@@ -0,0 +1,96 @@
+/* $OpenBSD: _float.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MACHINE__FLOAT_H_
+#define _MACHINE__FLOAT_H_
+
+#define __FLT_RADIX 2 /* b */
+#define __FLT_ROUNDS __flt_rounds()
+#define __FLT_EVAL_METHOD 0 /* no promotions */
+
+#define __FLT_MANT_DIG 24 /* p */
+#define __FLT_EPSILON 1.19209290E-7F /* b**(1-p) */
+#define __FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define __FLT_MIN_EXP (-125) /* emin */
+#define __FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define __FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define __FLT_MAX_EXP 128 /* emax */
+#define __FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define __FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define __DBL_MANT_DIG 53
+#define __DBL_EPSILON 2.2204460492503131E-16
+#define __DBL_DIG 15
+#define __DBL_MIN_EXP (-1021)
+#define __DBL_MIN 2.2250738585072014E-308
+#define __DBL_MIN_10_EXP (-307)
+#define __DBL_MAX_EXP 1024
+#define __DBL_MAX 1.7976931348623157E+308
+#define __DBL_MAX_10_EXP 308
+
+#ifdef __LDBL_MANT_DIG__
+#define __LDBL_MANT_DIG __LDBL_MANT_DIG__
+#define __LDBL_EPSILON __LDBL_EPSILON__
+#define __LDBL_DIG __LDBL_DIG__
+#define __LDBL_MIN_EXP __LDBL_MIN_EXP__
+#define __LDBL_MIN __LDBL_MIN__
+#define __LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
+#define __LDBL_MAX_EXP __LDBL_MAX_EXP__
+#define __LDBL_MAX __LDBL_MAX__
+#define __LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
+#else
+#define __LDBL_MANT_DIG DBL_MANT_DIG
+#define __LDBL_EPSILON DBL_EPSILON
+#define __LDBL_DIG DBL_DIG
+#define __LDBL_MIN_EXP DBL_MIN_EXP
+#define __LDBL_MIN DBL_MIN
+#define __LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define __LDBL_MAX_EXP DBL_MAX_EXP
+#define __LDBL_MAX DBL_MAX
+#define __LDBL_MAX_10_EXP DBL_MAX_10_EXP
+#endif
+
+#define __DECIMAL_DIG 17
+
+#endif /* _MACHINE__FLOAT_H_ */
diff --git a/sys/arch/arm64/include/_types.h b/sys/arch/arm64/include/_types.h
new file mode 100644
index 00000000000..5f003d9e632
--- /dev/null
+++ b/sys/arch/arm64/include/_types.h
@@ -0,0 +1,144 @@
+/* $OpenBSD: _types.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)types.h 8.3 (Berkeley) 1/5/94
+ * @(#)ansi.h 8.2 (Berkeley) 1/4/94
+ */
+
+#ifndef _MACHINE__TYPES_H_
+#define _MACHINE__TYPES_H_
+
+#if defined(_KERNEL)
+typedef struct label_t {
+ long val[11];
+} label_t;
+#endif
+
+/*
+ * _ALIGN(p) rounds p (pointer or byte index) up to a correctly-aligned
+ * value for all data types (int, long, ...). The result is an
+ * unsigned long and must be cast to any desired pointer type.
+ *
+ * _ALIGNED_POINTER is a boolean macro that checks whether an address
+ * is valid to fetch data elements of type t from on this architecture.
+ * This does not reflect the optimal alignment, just the possibility
+ * (within reasonable limits).
+ */
+#define _ALIGNBYTES (sizeof(long) - 1)
+#define _STACKALIGNBYTES 15
+#define _ALIGN(p) (((unsigned long)(p) + _ALIGNBYTES) & ~_ALIGNBYTES)
+#define _ALIGNED_POINTER(p,t) ((((unsigned long)(p)) & (sizeof(t) - 1)) == 0)
+
+/* 7.18.1.1 Exact-width integer types */
+typedef signed char __int8_t;
+typedef unsigned char __uint8_t;
+typedef short __int16_t;
+typedef unsigned short __uint16_t;
+typedef int __int32_t;
+typedef unsigned int __uint32_t;
+/* LONGLONG */
+typedef long long __int64_t;
+/* LONGLONG */
+typedef unsigned long long __uint64_t;
+
+/* 7.18.1.2 Minimum-width integer types */
+typedef __int8_t __int_least8_t;
+typedef __uint8_t __uint_least8_t;
+typedef __int16_t __int_least16_t;
+typedef __uint16_t __uint_least16_t;
+typedef __int32_t __int_least32_t;
+typedef __uint32_t __uint_least32_t;
+typedef __int64_t __int_least64_t;
+typedef __uint64_t __uint_least64_t;
+
+/* 7.18.1.3 Fastest minimum-width integer types */
+typedef __int32_t __int_fast8_t;
+typedef __uint32_t __uint_fast8_t;
+typedef __int32_t __int_fast16_t;
+typedef __uint32_t __uint_fast16_t;
+typedef __int32_t __int_fast32_t;
+typedef __uint32_t __uint_fast32_t;
+typedef __int64_t __int_fast64_t;
+typedef __uint64_t __uint_fast64_t;
+#define __INT_FAST8_MIN INT32_MIN
+#define __INT_FAST16_MIN INT32_MIN
+#define __INT_FAST32_MIN INT32_MIN
+#define __INT_FAST64_MIN INT64_MIN
+#define __INT_FAST8_MAX INT32_MAX
+#define __INT_FAST16_MAX INT32_MAX
+#define __INT_FAST32_MAX INT32_MAX
+#define __INT_FAST64_MAX INT64_MAX
+#define __UINT_FAST8_MAX UINT32_MAX
+#define __UINT_FAST16_MAX UINT32_MAX
+#define __UINT_FAST32_MAX UINT32_MAX
+#define __UINT_FAST64_MAX UINT64_MAX
+
+/* 7.18.1.4 Integer types capable of holding object pointers */
+typedef long __intptr_t;
+typedef unsigned long __uintptr_t;
+
+/* 7.18.1.5 Greatest-width integer types */
+typedef __int64_t __intmax_t;
+typedef __uint64_t __uintmax_t;
+
+/* Register size */
+typedef long __register_t;
+
+/* VM system types */
+typedef unsigned long __vaddr_t;
+typedef unsigned long __paddr_t;
+typedef unsigned long __vsize_t;
+typedef unsigned long __psize_t;
+
+/* Standard system types */
+typedef double __double_t;
+typedef float __float_t;
+typedef long __ptrdiff_t;
+typedef unsigned long __size_t;
+typedef long __ssize_t;
+#if defined(__GNUC__) && __GNUC__ >= 3
+typedef __builtin_va_list __va_list;
+#else
+typedef char * __va_list;
+#endif
+
+/* Wide character support types */
+#ifndef __cplusplus
+#ifdef __WCHAR_UNSIGNED__
+typedef unsigned int ___wchar_t;
+#else
+typedef int ___wchar_t;
+#endif
+#else
+typedef wchar_t ___wchar_t;
+#endif
+typedef void * __wctrans_t;
+typedef void * __wctype_t;
+
+#endif /* _MACHINE__TYPES_H_ */
diff --git a/sys/arch/arm64/include/apmvar.h b/sys/arch/arm64/include/apmvar.h
new file mode 100644
index 00000000000..4668424a84f
--- /dev/null
+++ b/sys/arch/arm64/include/apmvar.h
@@ -0,0 +1,121 @@
+/* $OpenBSD: apmvar.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2001 Alexander Guy
+ * Copyright (c) 1995 John T. Kohl
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 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.
+ *
+ */
+#ifndef _MACHINE_APMVAR_H_
+#define _MACHINE_APMVAR_H_
+
+#include <sys/ioccom.h>
+
+/* Advanced Power Management (v1.0 and v1.1 specification)
+ * functions/defines/etc.
+ */
+
+/* These definitions make up the heart of the user-land interface
+ * to the APM devices.
+ */
+
+#define APM_AC_OFF 0x00
+#define APM_AC_ON 0x01
+#define APM_AC_BACKUP 0x02
+#define APM_AC_UNKNOWN 0xff
+#define APM_BATT_HIGH 0x00
+#define APM_BATT_LOW 0x01
+#define APM_BATT_CRITICAL 0x02
+#define APM_BATT_CHARGING 0x03
+#define APM_BATT_UNKNOWN 0xff
+#define APM_BATT_LIFE_UNKNOWN 0xff
+
+#define APM_NOEVENT 0x0000
+#define APM_STANDBY_REQ 0x0001
+#define APM_SUSPEND_REQ 0x0002
+#define APM_NORMAL_RESUME 0x0003
+#define APM_CRIT_RESUME 0x0004 /* suspend/resume happened
+ without us */
+#define APM_BATTERY_LOW 0x0005
+#define APM_POWER_CHANGE 0x0006
+#define APM_UPDATE_TIME 0x0007
+#define APM_CRIT_SUSPEND_REQ 0x0008
+#define APM_USER_STANDBY_REQ 0x0009
+#define APM_USER_SUSPEND_REQ 0x000A
+#define APM_SYS_STANDBY_RESUME 0x000B
+#define APM_CAPABILITY_CHANGE 0x000C /* apm v1.2 */
+#define APM_EVENT_MASK 0xffff
+
+#define APM_EVENT_COMPOSE(t,i) ((((i) & 0x7fff) << 16)|((t) & APM_EVENT_MASK))
+#define APM_EVENT_TYPE(e) ((e) & APM_EVENT_MASK)
+#define APM_EVENT_INDEX(e) ((e) >> 16)
+
+/*
+ * LP (Laptop Package)
+ *
+ * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp>
+ *
+ * This software may be used, modified, copied, and distributed, in
+ * both source and binary form provided that the above copyright and
+ * these terms are retained. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with its
+ * use.
+ *
+ * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
+ */
+
+#define APM_BATTERY_ABSENT 4
+
+struct apm_power_info {
+ u_char battery_state;
+ u_char ac_state;
+ u_char battery_life;
+ u_char spare1;
+ u_int minutes_left; /* estimate */
+ u_int spare2[6];
+};
+
+struct apm_ctl {
+ u_int dev;
+ u_int mode;
+};
+
+#define APM_IOC_REJECT _IOW('A', 0, struct apm_event_info) /* reject request # */
+#define APM_IOC_STANDBY _IO('A', 1) /* put system into standby */
+#define APM_IOC_SUSPEND _IO('A', 2) /* put system into suspend */
+#define APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */
+#define APM_IOC_DEV_CTL _IOW('A', 5, struct apm_ctl) /* put device into mode */
+#define APM_IOC_PRN_CTL _IOW('A', 6, int ) /* driver power status msg */
+#define APM_PRINT_ON 0 /* driver power status displayed */
+#define APM_PRINT_OFF 1 /* driver power status not displayed */
+#define APM_PRINT_PCT 2 /* driver power status only displayed
+ if the percentage changes */
+#define APM_IOC_STANDBY_REQ _IO('A', 7) /* request standby */
+#define APM_IOC_SUSPEND_REQ _IO('A', 8) /* request suspend */
+#define APM_IOC_HIBERNATE _IO('A', 9) /* put system into hibernate */
+
+#endif /* _MACHINE_APMVAR_H_ */
diff --git a/sys/arch/arm64/include/armreg.h b/sys/arch/arm64/include/armreg.h
new file mode 100644
index 00000000000..f6e99ea0130
--- /dev/null
+++ b/sys/arch/arm64/include/armreg.h
@@ -0,0 +1,248 @@
+/* $OpenBSD: armreg.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2013, 2014 Andrew Turner
+ * Copyright (c) 2015 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * sponsorship from the FreeBSD Foundation.
+ *
+ * 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$
+ */
+
+#ifndef _MACHINE_ARMREG_H_
+#define _MACHINE_ARMREG_H_
+
+#define READ_SPECIALREG(reg) \
+({ uint64_t val; \
+ __asm __volatile("mrs %0, " __STRING(reg) : "=&r" (val)); \
+ val; \
+})
+#define WRITE_SPECIALREG(reg, val) \
+ __asm __volatile("msr " __STRING(reg) ", %0" : : "r"((uint64_t)val))
+
+/* CPACR_EL1 */
+#define CPACR_FPEN_MASK (0x3 << 20)
+#define CPACR_FPEN_TRAP_ALL1 (0x0 << 20) /* Traps from EL0 and EL1 */
+#define CPACR_FPEN_TRAP_EL0 (0x1 << 20) /* Traps from EL0 */
+#define CPACR_FPEN_TRAP_ALL2 (0x2 << 20) /* Traps from EL0 and EL1 */
+#define CPACR_FPEN_TRAP_NONE (0x3 << 20) /* No traps */
+#define CPACR_TTA (0x1 << 28)
+
+/* CTR_EL0 - Cache Type Register */
+#define CTR_DLINE_SHIFT 16
+#define CTR_DLINE_MASK (0xf << CTR_DLINE_SHIFT)
+#define CTR_DLINE_SIZE(reg) (((reg) & CTR_DLINE_MASK) >> CTR_DLINE_SHIFT)
+#define CTR_ILINE_SHIFT 0
+#define CTR_ILINE_MASK (0xf << CTR_ILINE_SHIFT)
+#define CTR_ILINE_SIZE(reg) (((reg) & CTR_ILINE_MASK) >> CTR_ILINE_SHIFT)
+
+/* ESR_ELx */
+#define ESR_ELx_ISS_MASK 0x00ffffff
+#define ISS_INSN_FnV (0x01 << 10)
+#define ISS_INSN_EA (0x01 << 9)
+#define ISS_INSN_S1PTW (0x01 << 7)
+#define ISS_INSN_IFSC_MASK (0x1f << 0)
+#define ISS_DATA_ISV (0x01 << 24)
+#define ISS_DATA_SAS_MASK (0x03 << 22)
+#define ISS_DATA_SSE (0x01 << 21)
+#define ISS_DATA_SRT_MASK (0x1f << 16)
+#define ISS_DATA_SF (0x01 << 15)
+#define ISS_DATA_AR (0x01 << 14)
+#define ISS_DATA_FnV (0x01 << 10)
+#define ISS_DATa_EA (0x01 << 9)
+#define ISS_DATa_CM (0x01 << 8)
+#define ISS_INSN_S1PTW (0x01 << 7)
+#define ISS_DATa_WnR (0x01 << 6)
+#define ISS_DATA_DFSC_MASK (0x1f << 0)
+#define ESR_ELx_IL (0x01 << 25)
+#define ESR_ELx_EC_SHIFT 26
+#define ESR_ELx_EC_MASK (0x3f << 26)
+#define ESR_ELx_EXCEPTION(esr) (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT)
+#define EXCP_UNKNOWN 0x00 /* Unkwn exception */
+#define EXCP_FP_SIMD 0x07 /* VFP/SIMD trap */
+#define EXCP_ILL_STATE 0x0e /* Illegal execution state */
+#define EXCP_SVC 0x15 /* SVC trap */
+#define EXCP_MSR 0x18 /* MSR/MRS trap */
+#define EXCP_INSN_ABORT_L 0x20 /* Instruction abort, from lower EL */
+#define EXCP_INSN_ABORT 0x21 /* Instruction abort, from same EL */
+#define EXCP_PC_ALIGN 0x22 /* PC alignment fault */
+#define EXCP_DATA_ABORT_L 0x24 /* Data abort, from lower EL */
+#define EXCP_DATA_ABORT 0x25 /* Data abort, from same EL */
+#define EXCP_SP_ALIGN 0x26 /* SP slignment fault */
+#define EXCP_TRAP_FP 0x2c /* Trapped FP exception */
+#define EXCP_SERROR 0x2f /* SError interrupt */
+#define EXCP_SOFTSTP_EL1 0x33 /* Software Step, from same EL */
+#define EXCP_WATCHPT_EL1 0x35 /* Watchpoint, from same EL */
+#define EXCP_BRK 0x3c /* Breakpoint */
+
+/* ICC_CTLR_EL1 */
+#define ICC_CTLR_EL1_EOIMODE (1U << 1)
+
+/* ICC_IAR1_EL1 */
+#define ICC_IAR1_EL1_SPUR (0x03ff)
+
+/* ICC_IGRPEN0_EL1 */
+#define ICC_IGRPEN0_EL1_EN (1U << 0)
+
+/* ICC_PMR_EL1 */
+#define ICC_PMR_EL1_PRIO_MASK (0xFFUL)
+
+/* ICC_SRE_EL1 */
+#define ICC_SRE_EL1_SRE (1U << 0)
+
+/* ICC_SRE_EL2 */
+#define ICC_SRE_EL2_EN (1U << 3)
+
+/* ID_AA64PFR0_EL1 */
+#define ID_AA64PFR0_EL0_MASK (0xf << 0)
+#define ID_AA64PFR0_EL1_MASK (0xf << 4)
+#define ID_AA64PFR0_EL2_MASK (0xf << 8)
+#define ID_AA64PFR0_EL3_MASK (0xf << 12)
+#define ID_AA64PFR0_FP_MASK (0xf << 16)
+#define ID_AA64PFR0_FP_IMPL (0x0 << 16) /* Floating-point implemented */
+#define ID_AA64PFR0_FP_NONE (0xf << 16) /* Floating-point not implemented */
+#define ID_AA64PFR0_ADV_SIMD_MASK (0xf << 20)
+#define ID_AA64PFR0_GIC_SHIFT (24)
+#define ID_AA64PFR0_GIC_BITS (0x4) /* Number of bits in GIC field */
+#define ID_AA64PFR0_GIC_MASK (0xf << ID_AA64PFR0_GIC_SHIFT)
+#define ID_AA64PFR0_GIC_CPUIF_EN (0x1 << ID_AA64PFR0_GIC_SHIFT)
+
+/* MAIR_EL1 - Memory Attribute Indirection Register */
+#define MAIR_ATTR_MASK(idx) (0xff << ((n)* 8))
+#define MAIR_ATTR(attr, idx) ((attr) << ((idx) * 8))
+
+/* SCTLR_EL1 - System Control Register */
+#define SCTLR_RES0 0xc8222400 /* Reserved, write 0 */
+#define SCTLR_RES1 0x30d00800 /* Reserved, write 1 */
+
+#define SCTLR_M 0x00000001
+#define SCTLR_A 0x00000002
+#define SCTLR_C 0x00000004
+#define SCTLR_SA 0x00000008
+#define SCTLR_SA0 0x00000010
+#define SCTLR_CP15BEN 0x00000020
+#define SCTLR_THEE 0x00000040
+#define SCTLR_ITD 0x00000080
+#define SCTLR_SED 0x00000100
+#define SCTLR_UMA 0x00000200
+#define SCTLR_I 0x00001000
+#define SCTLR_DZE 0x00004000
+#define SCTLR_UCT 0x00008000
+#define SCTLR_nTWI 0x00010000
+#define SCTLR_nTWE 0x00040000
+#define SCTLR_WXN 0x00080000
+#define SCTLR_EOE 0x01000000
+#define SCTLR_EE 0x02000000
+#define SCTLR_UCI 0x04000000
+
+/* SPSR_EL1 */
+/*
+ * When the exception is taken in AArch64:
+ * M[4] is 0 for AArch64 mode
+ * M[3:2] is the exception level
+ * M[1] is unused
+ * M[0] is the SP select:
+ * 0: always SP0
+ * 1: current ELs SP
+ */
+#define PSR_M_EL0t 0x00000000
+#define PSR_M_EL1t 0x00000004
+#define PSR_M_EL1h 0x00000005
+#define PSR_M_EL2t 0x00000008
+#define PSR_M_EL2h 0x00000009
+#define PSR_M_MASK 0x0000001f
+
+#define PSR_F 0x00000040
+#define PSR_I 0x00000080
+#define PSR_A 0x00000100
+#define PSR_D 0x00000200
+#define PSR_IL 0x00100000
+#define PSR_SS 0x00200000
+#define PSR_V 0x10000000
+#define PSR_C 0x20000000
+#define PSR_Z 0x40000000
+#define PSR_N 0x80000000
+
+/* TCR_EL1 - Translation Control Register */
+#define TCR_ASID_16 (1 << 36)
+
+#define TCR_IPS_SHIFT 32
+#define TCR_IPS_32BIT (0 << TCR_IPS_SHIFT)
+#define TCR_IPS_36BIT (1 << TCR_IPS_SHIFT)
+#define TCR_IPS_40BIT (2 << TCR_IPS_SHIFT)
+#define TCR_IPS_42BIT (3 << TCR_IPS_SHIFT)
+#define TCR_IPS_44BIT (4 << TCR_IPS_SHIFT)
+#define TCR_IPS_48BIT (5 << TCR_IPS_SHIFT)
+
+#define TCR_TG1_SHIFT 30
+#define TCR_TG1_16K (1 << TCR_TG1_SHIFT)
+#define TCR_TG1_4K (2 << TCR_TG1_SHIFT)
+#define TCR_TG1_64K (3 << TCR_TG1_SHIFT)
+
+#define TCR_SH0_SHIFT 12
+#define TCR_SH1_SHIFT 28
+#define TCR_SH0(x) ((x) << TCR_SH0_SHIFT)
+#define TCR_SH1(x) ((x) << TCR_SH1_SHIFT)
+#define TCR_ORGN1_SHIFT 26
+#define TCR_IRGN1_SHIFT 24
+#define TCR_ORGN0_SHIFT 10
+#define TCR_IRGN0_SHIFT 8
+#define TCR_ORGNx(x) (((x) << TCR_ORGN1_SHIFT)|((x) << TCR_ORGN0_SHIFT))
+#define TCR_IRGNx(x) (((x) << TCR_IRGN1_SHIFT)|((x) << TCR_IRGN0_SHIFT))
+#define TCR_SH1(x) ((x) << TCR_SH1_SHIFT)
+#define TCR_T1SZ_SHIFT 16
+#define TCR_T0SZ_SHIFT 0
+#define TCR_TxSZ(x) (((x) << TCR_T1SZ_SHIFT) | ((x) << TCR_T0SZ_SHIFT))
+
+/* Saved Program Status Register */
+#define DBG_SPSR_SS (0x1 << 21)
+
+/* Monitor Debug System Control Register */
+#define DBG_MDSCR_SS (0x1 << 0)
+#define DBG_MDSCR_KDE (0x1 << 13)
+#define DBG_MDSCR_MDE (0x1 << 15)
+
+
+/* Individual CPUs are probably best IDed by everything but the revision. */
+#define CPU_ID_CPU_MASK 0xfffffff0
+
+/* ARM64 CPUs */
+#define CPU_ID_CORTEX_A53 0x410fd030
+#define CPU_ID_CORTEX_A53_R1 0x411fd030
+#define CPU_ID_CORTEX_A53_MASK 0xff0ffff0
+#define CPU_ID_CORTEX_A57 0x410fd070
+#define CPU_ID_CORTEX_A57_R1 0x411fd070
+#define CPU_ID_CORTEX_A57_MASK 0xff0ffff0
+#define CPU_ID_CORTEX_A72 0x410fd080
+#define CPU_ID_CORTEX_A72_R1 0x411fd080
+#define CPU_ID_CORTEX_A57_MASK 0xff0ffff0
+
+
+#define I_bit (1 << 7) /* IRQ disable */
+#define F_bit 0 /* FIQ disable - not actually used */
+
+#define INSN_SIZE 4
+
+#endif /* !_MACHINE_ARMREG_H_ */
diff --git a/sys/arch/arm64/include/asm.h b/sys/arch/arm64/include/asm.h
new file mode 100644
index 00000000000..1aacb7fc68e
--- /dev/null
+++ b/sys/arch/arm64/include/asm.h
@@ -0,0 +1,146 @@
+/* $OpenBSD: asm.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: asm.h,v 1.4 2001/07/16 05:43:32 matt Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)asm.h 5.5 (Berkeley) 5/7/91
+ */
+
+#ifndef _MACHINE_ASM_H_
+#define _MACHINE_ASM_H_
+
+#ifdef __ELF__
+# define _C_LABEL(x) x
+#else
+# ifdef __STDC__
+# define _C_LABEL(x) _ ## x
+# else
+# define _C_LABEL(x) _/**/x
+# endif
+#endif
+#define _ASM_LABEL(x) x
+
+#ifdef __STDC__
+# define __CONCAT(x,y) x ## y
+# define __STRING(x) #x
+#else
+# define __CONCAT(x,y) x/**/y
+# define __STRING(x) "x"
+#endif
+
+#ifndef _ALIGN_TEXT
+# define _ALIGN_TEXT .align 0
+#endif
+
+/*
+ * gas/arm uses @ as a single comment character and thus cannot be used here
+ * Instead it recognised the # instead of an @ symbols in .type directives
+ * We define a couple of macros so that assembly code will not be dependant
+ * on one or the other.
+ */
+#define _ASM_TYPE_FUNCTION #function
+#define _ASM_TYPE_OBJECT #object
+#define _ENTRY(x) \
+ .text; _ALIGN_TEXT; .globl x; .type x,_ASM_TYPE_FUNCTION; x:
+
+#ifdef GPROF
+# define _PROF_PROLOGUE \
+ stp x29, x30, [sp, #-16]!; \
+ mov fp, sp; \
+ bl __mcount; \
+ ldp x29, x30, [sp], #16;
+#else
+# define _PROF_PROLOGUE
+#endif
+
+#define ENTRY(y) _ENTRY(_C_LABEL(y)); _PROF_PROLOGUE
+#define ENTRY_NP(y) _ENTRY(_C_LABEL(y))
+#define ASENTRY(y) _ENTRY(_ASM_LABEL(y)); _PROF_PROLOGUE
+#define ASENTRY_NP(y) _ENTRY(_ASM_LABEL(y))
+#define END(y) .size y, . - y
+#define EENTRY(sym) .globl sym; sym:
+#define EEND(sym)
+
+
+#define ASMSTR .asciz
+
+#if defined(__ELF__) && defined(__PIC__)
+#ifdef __STDC__
+#define PIC_SYM(x,y) x ## ( ## y ## )
+#else
+#define PIC_SYM(x,y) x/**/(/**/y/**/)
+#endif
+#else
+#define PIC_SYM(x,y) x
+#endif
+
+#ifdef __ELF__
+#define RCSID(x) .section ".ident"; .asciz x
+#else
+#define RCSID(x) .text; .asciz x
+#endif
+
+#ifdef __ELF__
+#define STRONG_ALIAS(alias,sym) \
+ .global alias; \
+ alias = sym
+#define WEAK_ALIAS(alias,sym) \
+ .weak alias; \
+ alias = sym
+#endif
+
+#ifdef __STDC__
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg ## ,30,0,0,0 ; \
+ .stabs __STRING(_C_LABEL(sym)) ## ,1,0,0,0
+#elif defined(__ELF__)
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg,30,0,0,0 ; \
+ .stabs __STRING(sym),1,0,0,0
+#else
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg,30,0,0,0 ; \
+ .stabs __STRING(_/**/sym),1,0,0,0
+#endif /* __STDC__ */
+
+
+/*
+ * Sets the trap fault handler. The exception handler will return to the
+ * address in the handler register on a data abort or the xzr register to
+ * clear the handler. The tmp parameter should be a register able to hold
+ * the temporary data.
+ */
+#define SET_FAULT_HANDLER(handler, tmp) \
+ ldr tmp, [x18, #CI_CURPCB]; /* Load the pcb */ \
+ str handler, [tmp, #PCB_ONFAULT] /* Set the handler */
+
+#endif /* !_MACHINE_ASM_H_ */
diff --git a/sys/arch/arm64/include/atomic.h b/sys/arch/arm64/include/atomic.h
new file mode 100644
index 00000000000..0c19c752bac
--- /dev/null
+++ b/sys/arch/arm64/include/atomic.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: atomic.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/* Public Domain */
+
+#ifndef _MACHINE_ATOMIC_H_
+#define _MACHINE_ATOMIC_H_
+
+#if defined(_KERNEL)
+//#include <sys/stdatomic.h>
+
+#define __membar(_f) do { __asm __volatile(_f ::: "memory"); } while (0)
+
+/* virtio needs MP membars even on SP kernels */
+#define virtio_membar_producer() __membar("")
+#define virtio_membar_consumer() __membar("")
+#define virtio_membar_sync() __membar("dmb sy") /* XXX dmb? */
+
+static inline void
+atomic_setbits_int(__volatile unsigned int *ptr, unsigned int val)
+{
+#if 0
+ //FIXME
+ atomic_fetch_or_explicit((atomic_uint *)ptr, val, memory_order_seq_cst);
+#else
+ *ptr |= val;
+#endif
+}
+static inline void
+atomic_clearbits_int(__volatile unsigned int *ptr, unsigned int val)
+{
+#if 0
+ //FIXME
+ atomic_fetch_and_explicit((atomic_uint *)ptr, ~val, memory_order_seq_cst);
+#else
+ *ptr &= ~val;
+#endif
+}
+#endif /* defined(_KERNEL) */
+#endif /* _MACHINE_ATOMIC_H_ */
diff --git a/sys/arch/arm64/include/bootconfig.h b/sys/arch/arm64/include/bootconfig.h
new file mode 100644
index 00000000000..f6f3598a2df
--- /dev/null
+++ b/sys/arch/arm64/include/bootconfig.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: bootconfig.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: bootconfig.h,v 1.2 2001/06/21 22:08:28 chris Exp $ */
+
+/*-
+ * Copyright (c) 2013 Andrew Turner <andrew@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$
+ */
+
+#ifndef _MACHINE_BOOTCONFIG_H_
+#define _MACHINE_BOOTCONFIG_H_
+
+#define MAX_BOOT_STRING 255
+extern char bootstring[MAX_BOOT_STRING];
+
+struct arm64_bootparams {
+ vaddr_t modulep;
+ vaddr_t kern_l1pt; /* L1 page table for the kernel */
+ uint64_t kern_delta;
+ vaddr_t kern_stack;
+ void *arg0; // passed to kernel in R0
+ void *arg1; // passed to kernel in R1
+ void *arg2; // passed to kernel in R2
+};
+
+extern paddr_t physmap[];
+extern u_int physmap_idx;
+
+
+void initarm(struct arm64_bootparams *);
+
+extern char *boot_file;
+
+#endif /* _MACHINE_BOOTCONFIG_H_ */
+
+/* End of bootconfig.h */
diff --git a/sys/arch/arm64/include/bus.h b/sys/arch/arm64/include/bus.h
new file mode 100644
index 00000000000..a681c9e929b
--- /dev/null
+++ b/sys/arch/arm64/include/bus.h
@@ -0,0 +1,530 @@
+/* $OpenBSD: bus.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2003-2004 Opsycon AB Sweden. 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 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.
+ */
+
+#ifndef _MACHINE_BUS_H_
+#define _MACHINE_BUS_H_
+
+#ifdef __STDC__
+#define CAT(a,b) a##b
+#define CAT3(a,b,c) a##b##c
+#else
+#define CAT(a,b) a/**/b
+#define CAT3(a,b,c) a/**/b/**/c
+#endif
+
+/*
+ * Bus access types.
+ */
+struct bus_space;
+typedef u_long bus_addr_t;
+typedef u_long bus_size_t;
+typedef u_long bus_space_handle_t;
+typedef struct bus_space *bus_space_tag_t;
+typedef struct bus_space bus_space_t;
+
+struct bus_space {
+ bus_addr_t bus_base;
+ void *bus_private;
+ u_int8_t (*_space_read_1)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t);
+ void (*_space_write_1)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t, u_int8_t);
+ u_int16_t (*_space_read_2)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t);
+ void (*_space_write_2)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t, u_int16_t);
+ u_int32_t (*_space_read_4)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t);
+ void (*_space_write_4)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t, u_int32_t);
+ u_int64_t (*_space_read_8)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t);
+ void (*_space_write_8)(bus_space_tag_t , bus_space_handle_t,
+ bus_size_t, u_int64_t);
+ void (*_space_read_raw_2)(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, u_int8_t *, bus_size_t);
+ void (*_space_write_raw_2)(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const u_int8_t *, bus_size_t);
+ void (*_space_read_raw_4)(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, u_int8_t *, bus_size_t);
+ void (*_space_write_raw_4)(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const u_int8_t *, bus_size_t);
+ void (*_space_read_raw_8)(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, u_int8_t *, bus_size_t);
+ void (*_space_write_raw_8)(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const u_int8_t *, bus_size_t);
+ int (*_space_map)(bus_space_tag_t , bus_addr_t,
+ bus_size_t, int, bus_space_handle_t *);
+ void (*_space_unmap)(bus_space_tag_t, bus_space_handle_t,
+ bus_size_t);
+ int (*_space_subregion)(bus_space_tag_t, bus_space_handle_t,
+ bus_size_t, bus_size_t, bus_space_handle_t *);
+ void * (*_space_vaddr)(bus_space_tag_t, bus_space_handle_t);
+};
+
+#define bus_space_read_1(t, h, o) (*(t)->_space_read_1)((t), (h), (o))
+#define bus_space_read_2(t, h, o) (*(t)->_space_read_2)((t), (h), (o))
+#define bus_space_read_4(t, h, o) (*(t)->_space_read_4)((t), (h), (o))
+#define bus_space_read_8(t, h, o) (*(t)->_space_read_8)((t), (h), (o))
+
+#define bus_space_write_1(t, h, o, v) (*(t)->_space_write_1)((t), (h), (o), (v))
+#define bus_space_write_2(t, h, o, v) (*(t)->_space_write_2)((t), (h), (o), (v))
+#define bus_space_write_4(t, h, o, v) (*(t)->_space_write_4)((t), (h), (o), (v))
+#define bus_space_write_8(t, h, o, v) (*(t)->_space_write_8)((t), (h), (o), (v))
+
+#define bus_space_read_raw_multi_2(t, h, a, b, l) \
+ (*(t)->_space_read_raw_2)((t), (h), (a), (b), (l))
+#define bus_space_read_raw_multi_4(t, h, a, b, l) \
+ (*(t)->_space_read_raw_4)((t), (h), (a), (b), (l))
+#define bus_space_read_raw_multi_8(t, h, a, b, l) \
+ (*(t)->_space_read_raw_8)((t), (h), (a), (b), (l))
+
+#define bus_space_write_raw_multi_2(t, h, a, b, l) \
+ (*(t)->_space_write_raw_2)((t), (h), (a), (b), (l))
+#define bus_space_write_raw_multi_4(t, h, a, b, l) \
+ (*(t)->_space_write_raw_4)((t), (h), (a), (b), (l))
+#define bus_space_write_raw_multi_8(t, h, a, b, l) \
+ (*(t)->_space_write_raw_8)((t), (h), (a), (b), (l))
+
+#define bus_space_map(t, o, s, c, p) (*(t)->_space_map)((t), (o), (s), (c), (p))
+#define bus_space_unmap(t, h, s) (*(t)->_space_unmap)((t), (h), (s))
+#define bus_space_subregion(t, h, o, s, p) \
+ (*(t)->_space_subregion)((t), (h), (o), (s), (p))
+
+#define BUS_SPACE_MAP_CACHEABLE 0x01
+#define BUS_SPACE_MAP_KSEG0 0x02
+#define BUS_SPACE_MAP_LINEAR 0x04
+#define BUS_SPACE_MAP_PREFETCHABLE 0x08
+
+#define bus_space_vaddr(t, h) (*(t)->_space_vaddr)((t), (h))
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_read_multi(n,m) \
+static __inline void \
+CAT(bus_space_read_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \
+ bus_size_t o, CAT3(u_int,m,_t) *x, size_t cnt) \
+{ \
+ while (cnt--) \
+ *x++ = CAT(bus_space_read_,n)(bst, bsh, o); \
+}
+
+bus_space_read_multi(1,8)
+bus_space_read_multi(2,16)
+bus_space_read_multi(4,32)
+bus_space_read_multi(8,64)
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_read_region(n,m) \
+static __inline void \
+CAT(bus_space_read_region_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \
+ bus_addr_t ba, CAT3(u_int,m,_t) *x, size_t cnt) \
+{ \
+ while (cnt--) \
+ *x++ = CAT(bus_space_read_,n)(bst, bsh, ba++); \
+}
+
+bus_space_read_region(1,8)
+bus_space_read_region(2,16)
+bus_space_read_region(4,32)
+bus_space_read_region(8,64)
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_read_raw_region(n,m) \
+static __inline void \
+CAT(bus_space_read_raw_region_,n)(bus_space_tag_t bst, \
+ bus_space_handle_t bsh, \
+ bus_addr_t ba, u_int8_t *x, size_t cnt) \
+{ \
+ cnt >>= ((n) >> 1); \
+ while (cnt--) { \
+ CAT(bus_space_read_raw_multi_,n)(bst, bsh, ba, x, (n)); \
+ ba += (n); \
+ x += (n); \
+ } \
+}
+
+bus_space_read_raw_region(2,16)
+bus_space_read_raw_region(4,32)
+bus_space_read_raw_region(8,64)
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_write_multi(n,m) \
+static __inline void \
+CAT(bus_space_write_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \
+ bus_size_t o, const CAT3(u_int,m,_t) *x, size_t cnt) \
+{ \
+ while (cnt--) { \
+ CAT(bus_space_write_,n)(bst, bsh, o, *x++); \
+ } \
+}
+
+bus_space_write_multi(1,8)
+bus_space_write_multi(2,16)
+bus_space_write_multi(4,32)
+bus_space_write_multi(8,64)
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_write_region(n,m) \
+static __inline void \
+CAT(bus_space_write_region_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \
+ bus_addr_t ba, const CAT3(u_int,m,_t) *x, size_t cnt) \
+{ \
+ while (cnt--) { \
+ CAT(bus_space_write_,n)(bst, bsh, ba, *x++); \
+ ba += sizeof(x); \
+ } \
+}
+
+bus_space_write_region(1,8)
+bus_space_write_region(2,16)
+bus_space_write_region(4,32)
+bus_space_write_region(8,64)
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_write_raw_region(n,m) \
+static __inline void \
+CAT(bus_space_write_raw_region_,n)(bus_space_tag_t bst, \
+ bus_space_handle_t bsh, \
+ bus_addr_t ba, const u_int8_t *x, size_t cnt) \
+{ \
+ cnt >>= ((n) >> 1); \
+ while (cnt--) { \
+ CAT(bus_space_write_raw_multi_,n)(bst, bsh, ba, x, (n)); \
+ ba += (n); \
+ x += (n); \
+ } \
+}
+
+bus_space_write_raw_region(2,16)
+bus_space_write_raw_region(4,32)
+bus_space_write_raw_region(8,64)
+
+/*----------------------------------------------------------------------------*/
+#define bus_space_set_region(n,m) \
+static __inline void \
+CAT(bus_space_set_region_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \
+ bus_addr_t ba, CAT3(u_int,m,_t) x, size_t cnt) \
+{ \
+ while (cnt--) { \
+ CAT(bus_space_write_,n)(bst, bsh, ba, x); \
+ ba += sizeof(x); \
+ } \
+}
+
+bus_space_set_region(1,8)
+bus_space_set_region(2,16)
+bus_space_set_region(4,32)
+bus_space_set_region(8,64)
+
+/*----------------------------------------------------------------------------*/
+static __inline void
+bus_space_copy_1(void *v, bus_space_handle_t h1, bus_size_t o1,
+ bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
+{
+ char *s = (char *)(h1 + o1);
+ char *d = (char *)(h2 + o2);
+
+ while (c--)
+ *d++ = *s++;
+}
+
+
+static __inline void
+bus_space_copy_2(void *v, bus_space_handle_t h1, bus_size_t o1,
+ bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
+{
+ short *s = (short *)(h1 + o1);
+ short *d = (short *)(h2 + o2);
+
+ while (c--)
+ *d++ = *s++;
+}
+
+static __inline void
+bus_space_copy_4(void *v, bus_space_handle_t h1, bus_size_t o1,
+ bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
+{
+ int *s = (int *)(h1 + o1);
+ int *d = (int *)(h2 + o2);
+
+ while (c--)
+ *d++ = *s++;
+}
+
+static __inline void
+bus_space_copy_8(void *v, bus_space_handle_t h1, bus_size_t o1,
+ bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
+{
+ int64_t *s = (int64_t *)(h1 + o1);
+ int64_t *d = (int64_t *)(h2 + o2);
+
+ while (c--)
+ *d++ = *s++;
+}
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Bus read/write barrier methods.
+ *
+ * void bus_space_barrier(bus_space_tag_t tag,
+ * bus_space_handle_t bsh, bus_size_t offset,
+ * bus_size_t len, int flags);
+ *
+ */
+static inline void
+bus_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset,
+ bus_size_t length, int flags)
+{
+ __asm__ volatile ("dsb sy" ::: "memory");
+}
+#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */
+#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */
+
+#define BUS_DMA_WAITOK 0x0000
+#define BUS_DMA_NOWAIT 0x0001
+#define BUS_DMA_ALLOCNOW 0x0002
+#define BUS_DMA_COHERENT 0x0008
+#define BUS_DMA_BUS1 0x0010 /* placeholders for bus functions... */
+#define BUS_DMA_BUS2 0x0020
+#define BUS_DMA_BUS3 0x0040
+#define BUS_DMA_BUS4 0x0080
+#define BUS_DMA_READ 0x0100 /* mapping is device -> memory only */
+#define BUS_DMA_WRITE 0x0200 /* mapping is memory -> device only */
+#define BUS_DMA_STREAMING 0x0400 /* hint: sequential, unidirectional */
+#define BUS_DMA_ZERO 0x0800 /* zero memory in dmamem_alloc */
+#define BUS_DMA_NOCACHE 0x1000
+
+/* Forwards needed by prototypes below. */
+struct mbuf;
+struct proc;
+struct uio;
+
+#define BUS_DMASYNC_POSTREAD 0x0001
+#define BUS_DMASYNC_POSTWRITE 0x0002
+#define BUS_DMASYNC_PREREAD 0x0004
+#define BUS_DMASYNC_PREWRITE 0x0008
+
+typedef struct machine_bus_dma_tag *bus_dma_tag_t;
+typedef struct machine_bus_dmamap *bus_dmamap_t;
+
+/*
+ * bus_dma_segment_t
+ *
+ * Describes a single contiguous DMA transaction. Values
+ * are suitable for programming into DMA registers.
+ */
+struct machine_bus_dma_segment {
+ bus_addr_t ds_addr; /* DMA address */
+ bus_size_t ds_len; /* length of transfer */
+
+ paddr_t _ds_paddr; /* CPU address */
+ vaddr_t _ds_vaddr; /* CPU address */
+};
+typedef struct machine_bus_dma_segment bus_dma_segment_t;
+
+/*
+ * bus_dma_tag_t
+ *
+ * A machine-dependent opaque type describing the implementation of
+ * DMA for a given bus.
+ */
+
+struct machine_bus_dma_tag {
+ void *_cookie; /* cookie used in the guts */
+
+ /*
+ * DMA mapping methods.
+ */
+ int (*_dmamap_create)(bus_dma_tag_t , bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *);
+ void (*_dmamap_destroy)(bus_dma_tag_t , bus_dmamap_t);
+ int (*_dmamap_load)(bus_dma_tag_t , bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int);
+ int (*_dmamap_load_mbuf)(bus_dma_tag_t , bus_dmamap_t,
+ struct mbuf *, int);
+ int (*_dmamap_load_uio)(bus_dma_tag_t , bus_dmamap_t,
+ struct uio *, int);
+ int (*_dmamap_load_raw)(bus_dma_tag_t , bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int);
+ int (*_dmamap_load_buffer)(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int, paddr_t *, int *, int);
+ void (*_dmamap_unload)(bus_dma_tag_t , bus_dmamap_t);
+ void (*_dmamap_sync)(bus_dma_tag_t , bus_dmamap_t,
+ bus_addr_t, bus_size_t, int);
+
+ /*
+ * DMA memory utility functions.
+ */
+ int (*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int);
+ void (*_dmamem_free)(bus_dma_tag_t, bus_dma_segment_t *, int);
+ int (*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *,
+ int, size_t, caddr_t *, int);
+ void (*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t);
+ paddr_t (*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *,
+ int, off_t, int, int);
+
+ /*
+ * internal memory address translation information.
+ */
+ bus_addr_t _dma_mask;
+};
+
+#define bus_dmamap_create(t, s, n, m, b, f, p) \
+ (*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p))
+#define bus_dmamap_destroy(t, p) \
+ (*(t)->_dmamap_destroy)((t), (p))
+#define bus_dmamap_load(t, m, b, s, p, f) \
+ (*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f))
+#define bus_dmamap_load_mbuf(t, m, b, f) \
+ (*(t)->_dmamap_load_mbuf)((t), (m), (b), (f))
+#define bus_dmamap_load_uio(t, m, u, f) \
+ (*(t)->_dmamap_load_uio)((t), (m), (u), (f))
+#define bus_dmamap_load_raw(t, m, sg, n, s, f) \
+ (*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f))
+#define bus_dmamap_unload(t, p) \
+ (*(t)->_dmamap_unload)((t), (p))
+#define bus_dmamap_sync(t, p, a, l, o) \
+ (void)((t)->_dmamap_sync ? \
+ (*(t)->_dmamap_sync)((t), (p), (a), (l), (o)) : (void)0)
+
+#define bus_dmamem_alloc(t, s, a, b, sg, n, r, f) \
+ (*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f))
+#define bus_dmamem_free(t, sg, n) \
+ (*(t)->_dmamem_free)((t), (sg), (n))
+#define bus_dmamem_map(t, sg, n, s, k, f) \
+ (*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f))
+#define bus_dmamem_unmap(t, k, s) \
+ (*(t)->_dmamem_unmap)((t), (k), (s))
+#define bus_dmamem_mmap(t, sg, n, o, p, f) \
+ (*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
+
+int _dmamap_create(bus_dma_tag_t, bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *);
+void _dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
+int _dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int);
+int _dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int);
+int _dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int);
+int _dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int);
+int _dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int, paddr_t *, int *, int);
+void _dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
+void _dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+ bus_size_t, int);
+
+int _dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int);
+void _dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int);
+int _dmamem_map(bus_dma_tag_t, bus_dma_segment_t *,
+ int, size_t, caddr_t *, int);
+void _dmamem_unmap(bus_dma_tag_t, caddr_t, size_t);
+paddr_t _dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, int, off_t, int, int);
+int _dmamem_alloc_range(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t,
+ bus_dma_segment_t *, int, int *, int, paddr_t, paddr_t);
+
+/*
+ * bus_dmamap_t
+ *
+ * Describes a DMA mapping.
+ */
+struct machine_bus_dmamap {
+ /*
+ * PRIVATE MEMBERS: not for use by machine-independent code.
+ */
+ bus_size_t _dm_size; /* largest DMA transfer mappable */
+ int _dm_segcnt; /* number of segs this map can map */
+ bus_size_t _dm_maxsegsz; /* largest possible segment */
+ bus_size_t _dm_boundary; /* don't cross this */
+ int _dm_flags; /* misc. flags */
+
+ void *_dm_cookie; /* cookie for bus-specific functions */
+
+ /*
+ * PUBLIC MEMBERS: these are used by machine-independent code.
+ */
+ bus_size_t dm_mapsize; /* size of the mapping */
+ int dm_nsegs; /* # valid segments in mapping */
+ bus_dma_segment_t dm_segs[1]; /* segments; variable length */
+};
+
+int generic_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+void generic_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+int generic_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ bus_size_t, bus_space_handle_t *);
+void *generic_space_vaddr(bus_space_tag_t, bus_space_handle_t);
+uint8_t generic_space_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t generic_space_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint32_t generic_space_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint64_t generic_space_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void generic_space_read_raw_2(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, uint8_t *, bus_size_t);
+void generic_space_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint8_t);
+void generic_space_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint16_t);
+void generic_space_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint32_t);
+void generic_space_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint64_t);
+void generic_space_write_raw_2(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const uint8_t *, bus_size_t);
+void generic_space_read_raw_4(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, uint8_t *, bus_size_t);
+void generic_space_write_raw_4(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const uint8_t *, bus_size_t);
+void generic_space_read_raw_8(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, uint8_t *, bus_size_t);
+void generic_space_write_raw_8(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const uint8_t *, bus_size_t);
+
+uint8_t a4x_space_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint16_t a4x_space_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint32_t a4x_space_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+uint64_t a4x_space_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
+void a4x_space_read_raw_2(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, uint8_t *, bus_size_t);
+void a4x_space_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint8_t);
+void a4x_space_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint16_t);
+void a4x_space_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint32_t);
+void a4x_space_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t,
+ uint64_t);
+void a4x_space_write_raw_2(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const uint8_t *, bus_size_t);
+void a4x_space_read_raw_4(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, uint8_t *, bus_size_t);
+void a4x_space_write_raw_4(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const uint8_t *, bus_size_t);
+void a4x_space_read_raw_8(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, uint8_t *, bus_size_t);
+void a4x_space_write_raw_8(bus_space_tag_t, bus_space_handle_t,
+ bus_addr_t, const uint8_t *, bus_size_t);
+
+#endif /* _MACHINE_BUS_H_ */
diff --git a/sys/arch/arm64/include/cdefs.h b/sys/arch/arm64/include/cdefs.h
new file mode 100644
index 00000000000..e7cb19812b9
--- /dev/null
+++ b/sys/arch/arm64/include/cdefs.h
@@ -0,0 +1,16 @@
+/* $OpenBSD: cdefs.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+#ifndef _MACHINE_CDEFS_H_
+#define _MACHINE_CDEFS_H_
+
+#define __strong_alias(alias,sym) \
+ __asm__(".global " __STRING(alias) " ; " __STRING(alias) \
+ " = " __STRING(sym))
+#define __weak_alias(alias,sym) \
+ __asm__(".weak " __STRING(alias) " ; " __STRING(alias) \
+ " = " __STRING(sym))
+#define __warn_references(sym,msg) \
+ __asm__(".section .gnu.warning." __STRING(sym) \
+ " ; .ascii \"" msg "\" ; .text")
+
+#endif /* !_MACHINE_CDEFS_H_ */
diff --git a/sys/arch/arm64/include/conf.h b/sys/arch/arm64/include/conf.h
new file mode 100644
index 00000000000..d4d33375847
--- /dev/null
+++ b/sys/arch/arm64/include/conf.h
@@ -0,0 +1,82 @@
+/* $OpenBSD: conf.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */
+
+/*
+ * Copyright (c) 1996 Christos Zoulas. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 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.
+ */
+
+#ifndef _MACHINE_CONF_H_
+#define _MACHINE_CONF_H_
+
+#include <sys/conf.h>
+
+#define mmread mmrw
+#define mmwrite mmrw
+cdev_decl(mm);
+
+
+/*
+ * These numbers have to be in sync with bdevsw/cdevsw.
+ */
+
+#define BMAJ_WD 0
+#define BMAJ_SW 1
+#define BMAJ_SD 4
+#define BMAJ_ST 5
+
+#define CMAJ_MM 2
+#define CMAJ_PTS 5
+#define CMAJ_PTC 6
+#define CMAJ_COM 8
+#define CMAJ_WSDISPLAY 12
+#define CMAJ_ST 14
+#define CMAJ_LPT 16
+#define CMAJ_CH 17
+#define CMAJ_UK 20
+#define CMAJ_BPF 23
+#define CMAJ_TUN 40
+#define CMAJ_AUDIO 42
+#define CMAJ_VIDEO 44
+#define CMAJ_BKTR 49
+#define CMAJ_MIDI 52
+#define CMAJ_USB 61
+#define CMAJ_UHID 62
+#define CMAJ_UGEN 63
+#define CMAJ_ULPT 64
+#define CMAJ_UCOM 66
+#define CMAJ_WSKBD 67
+#define CMAJ_WSMOUSE 68
+#ifdef USER_PCICONF
+#define CMAJ_PCI 72
+#endif
+#define CMAJ_RADIO 76
+#define CMAJ_DRM 87
+#define CMAJ_GPIO 88
+#define CMAJ_VSCSI 89
+
+#endif /* _MACHINE_CONF_H_ */
diff --git a/sys/arch/arm64/include/cpu.h b/sys/arch/arm64/include/cpu.h
new file mode 100644
index 00000000000..2497cb33ccf
--- /dev/null
+++ b/sys/arch/arm64/include/cpu.h
@@ -0,0 +1,264 @@
+/* $OpenBSD: cpu.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _MACHINE_CPU_H_
+#define _MACHINE_CPU_H_
+
+/*
+ * User-visible definitions
+ */
+
+/* CTL_MACHDEP definitions. */
+/* None for now */
+#define CPU_MAXID 0 /* number of valid machdep ids */
+
+#define CTL_MACHDEP_NAMES { \
+}
+
+#ifdef _KERNEL
+
+/*
+ * Kernel-only definitions
+ */
+
+#include <machine/intr.h>
+#ifndef _LOCORE
+#include <machine/frame.h>
+#endif /* !_LOCORE */
+
+#include <machine/armreg.h>
+
+#ifndef _LOCORE
+
+/* All the CLKF_* macros take a struct clockframe * as an argument. */
+
+#define clockframe trapframe
+/*
+ * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the
+ * frame came from USR mode or not.
+ */
+#define CLKF_USERMODE(frame) ((frame->tf_elr & (1ul << 63)) == 0)
+
+/*
+ * CLKF_INTR: True if we took the interrupt from inside another
+ * interrupt handler.
+ */
+#define CLKF_INTR(frame) (curcpu()->ci_idepth > 1)
+
+/*
+ * CLKF_PC: Extract the program counter from a clockframe
+ */
+#define CLKF_PC(frame) (frame->tf_elr)
+
+/*
+ * PROC_PC: Find out the program counter for the given process.
+ */
+#define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_elr)
+#define PROC_STACK(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sp)
+
+/* The address of the vector page. */
+extern vaddr_t vector_page;
+void arm32_vector_init(vaddr_t, int);
+
+/*
+ * Per-CPU information. For now we assume one CPU.
+ */
+
+#include <sys/device.h>
+#include <sys/sched.h>
+struct cpu_info {
+ struct device *ci_dev; /* Device corresponding to this CPU */
+ struct cpu_info *ci_next;
+ struct schedstate_percpu ci_schedstate; /* scheduler state */
+
+ struct proc *ci_curproc;
+ struct pmap *ci_curpm;
+ struct proc *ci_fpuproc;
+ u_int32_t ci_cpuid;
+ u_int32_t ci_randseed;
+
+ struct pcb *ci_curpcb;
+ struct pcb *ci_idle_pcb;
+
+ u_int32_t ci_ctrl; /* The CPU control register */
+
+ uint32_t ci_cpl;
+ uint32_t ci_ipending;
+ uint32_t ci_idepth;
+#ifdef DIAGNOSTIC
+ int ci_mutex_level;
+#endif
+ int ci_want_resched;
+
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
+};
+
+static inline struct cpu_info *
+curcpu(void)
+{
+ struct cpu_info *__ci = NULL;
+ __asm __volatile("mrs %0, tpidr_el1" : "=r" (__ci));
+ return (__ci);
+}
+
+extern struct cpu_info cpu_info_primary;
+extern struct cpu_info *cpu_info_list;
+
+#ifndef MULTIPROCESSOR
+#define cpu_number() 0
+#define CPU_IS_PRIMARY(ci) 1
+#define CPU_INFO_ITERATOR int
+#define CPU_INFO_FOREACH(cii, ci) \
+ for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL)
+#define CPU_INFO_UNIT(ci) 0
+#define MAXCPUS 1
+#define cpu_unidle(ci)
+#else
+#define cpu_number() (curcpu()->ci_cpuid)
+#define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary)
+#define CPU_INFO_ITERATOR int
+#define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \
+ ci != NULL; ci = ci->ci_next)
+
+#define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0)
+#define MAXCPUS 8
+#define cpu_unidle(ci)
+
+extern struct cpu_info *cpu_info[MAXCPUS];
+
+void cpu_boot_secondary_processors(void);
+#endif /* !MULTIPROCESSOR */
+
+
+#define curpcb curcpu()->ci_curpcb
+
+/*
+ * Scheduling glue
+ */
+#define aston(p) ((p)->p_md.md_astpending = 1)
+#define setsoftast() aston(curcpu()->ci_curproc)
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+
+#define signotify(p) setsoftast()
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+void need_resched(struct cpu_info *);
+#define clear_resched(ci) ((ci)->ci_want_resched = 0)
+
+/*
+ * Give a profiling tick to the current process when the user profiling
+ * buffer pages are invalid. On the i386, request an ast to send us
+ * through trap(), marking the proc as needing a profiling tick.
+ */
+#define need_proftick(p) aston(p)
+
+// asm code to start new kernel contexts.
+void proc_trampoline(void);
+void child_trampoline(void);
+
+/*
+ * Random cruft
+ */
+void dumpconf(void);
+
+// cpuswitch.S
+struct pcb;
+void savectx (struct pcb *pcb);
+
+// machdep.h
+void bootsync (int);
+
+// fault.c
+int badaddr_read (void *, size_t, void *);
+
+// syscall.c
+void svc_handler (trapframe_t *);
+
+/* machine_machdep.c */
+void board_startup(void);
+
+// functions to manipulate interrupt state
+static __inline uint32_t
+get_daif()
+{
+ uint32_t daif;
+
+ __asm volatile ("mrs %x0, daif": "=r"(daif));
+ return daif;
+}
+
+static __inline void
+restore_daif(uint32_t daif)
+{
+ __asm volatile ("msr daif, %x0":: "r"(daif));
+}
+
+static __inline void
+enable_irq_daif()
+{
+ __asm volatile ("msr daifclr, #2");
+}
+
+static __inline void
+disable_irq_daif()
+{
+ __asm volatile ("msr daifset, #2");
+}
+
+static __inline uint32_t
+disable_irq_daif_ret()
+{
+ uint32_t daif;
+ __asm volatile ("mrs %x0, daif": "=r"(daif));
+ __asm volatile ("msr daifset, #2");
+ return daif;
+}
+
+#define get_interrupts(mask) \
+ (__get_daif())
+
+#define disable_interrupts() \
+ disable_irq_daif_ret()
+
+#define enable_interrupts() \
+ enable_irq_daif()
+
+#define restore_interrupts(old_daif) \
+ restore_daif(old_daif)
+
+void delay (unsigned);
+#define DELAY(x) delay(x)
+
+#endif /* !_LOCORE */
+
+#endif /* _KERNEL */
+
+#ifdef MULTIPROCESSOR
+#include <sys/mplock.h>
+#endif /* MULTIPROCESSOR */
+
+#endif /* !_MACHINE_CPU_H_ */
+
+/* End of cpu.h */
diff --git a/sys/arch/arm64/include/db_machdep.h b/sys/arch/arm64/include/db_machdep.h
new file mode 100644
index 00000000000..7f97a74eaf5
--- /dev/null
+++ b/sys/arch/arm64/include/db_machdep.h
@@ -0,0 +1,92 @@
+/* $OpenBSD: db_machdep.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: db_machdep.h,v 1.5 2001/11/22 18:00:00 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1996 Scott K Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _MACHINE_DB_MACHDEP_H_
+#define _MACHINE_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+#include <uvm/uvm_extern.h>
+#include <machine/armreg.h>
+#include <machine/frame.h>
+#include <machine/trap.h>
+
+/* end of mangling */
+
+typedef vaddr_t db_addr_t; /* address - unsigned */
+typedef long db_expr_t; /* expression - signed */
+
+typedef trapframe_t db_regs_t;
+
+extern db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_lr)
+#define SET_PC_REGS(regs, value) (regs)->tf_lr = (register_t)(value)
+
+#define BKPT_INST (KERNEL_BREAKPOINT) /* breakpoint instruction */
+#define BKPT_SIZE (INSN_SIZE) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+/*#define FIXUP_PC_AFTER_BREAK(regs) ((regs)->tf_lr -= BKPT_SIZE)*/
+
+#define T_BREAKPOINT (1)
+
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAKPOINT)
+#define IS_WATCHPOINT_TRAP(type, code) (0)
+
+// ALL BROKEN!!!
+#define inst_trap_return(ins) ((ins) == 0 && (ins) == 1)
+#define inst_return(ins) ((ins) == 0 && (ins) == 1)
+
+#define inst_call(ins) ((ins) == 0 && (ins) == 1)
+#define inst_branch(ins) ((ins) == 0 && (ins) == 1)
+#define inst_unconditional_flow_transfer(ins) (0)
+
+#define getreg_val (0)
+#define next_instr_address(pc, bd) ((bd) ? (pc) : ((pc) + INSN_SIZE))
+
+#define DB_MACHINE_COMMANDS
+
+#define SOFTWARE_SSTEP
+
+db_addr_t db_branch_taken(u_int inst, db_addr_t pc, db_regs_t *regs);
+int kdb_trap (int, db_regs_t *);
+void db_machine_init (void);
+
+#define branch_taken(ins, pc, fun, regs) \
+ db_branch_taken((ins), (pc), (regs))
+
+void db_show_frame_cmd(db_expr_t, int, db_expr_t, char *);
+
+#endif /* _MACHINE_DB_MACHDEP_H_ */
diff --git a/sys/arch/arm64/include/disklabel.h b/sys/arch/arm64/include/disklabel.h
new file mode 100644
index 00000000000..cdd57e1bbb1
--- /dev/null
+++ b/sys/arch/arm64/include/disklabel.h
@@ -0,0 +1,25 @@
+/* $OpenBSD: disklabel.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef _MACHINE_DISKLABEL_H_
+#define _MACHINE_DISKLABEL_H_
+
+#define LABELSECTOR 1 /* sector containing label */
+#define LABELOFFSET 0 /* offset of label in sector */
+#define MAXPARTITIONS 16 /* number of partitions */
+
+#endif /* _MACHINE_DISKLABEL_H_ */
diff --git a/sys/arch/arm64/include/endian.h b/sys/arch/arm64/include/endian.h
new file mode 100644
index 00000000000..98e3f0f949f
--- /dev/null
+++ b/sys/arch/arm64/include/endian.h
@@ -0,0 +1,37 @@
+/* $OpenBSD: endian.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+#ifndef _MACHINE_ENDIAN_H_
+#define _MACHINE_ENDIAN_H_
+
+#define __swap32md(x) __statement({ \
+ __uint32_t __swap32md_x; \
+ \
+ __asm ("rev %w0, %w1" : "=r" (__swap32md_x) : "r"(x)); \
+ __swap32md_x; \
+})
+
+#define __swap64md(x) __statement({ \
+ __uint64_t __swap64md_x; \
+ \
+ __asm ("rev %x0, %x1" : "=r" (__swap64md_x) : "r"(x)); \
+ __swap64md_x; \
+})
+
+#define __swap16md(x) __statement({ \
+ __uint16_t __swap16md_x; \
+ \
+ __asm ("rev16 %w0, %w1" : "=r" (__swap16md_x) : "r"(x)); \
+ __swap16md_x; \
+})
+
+/* Tell sys/endian.h we have MD variants of the swap macros. */
+#define __HAVE_MD_SWAP
+
+
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#define __STRICT_ALIGNMENT
+
+#ifndef __FROM_SYS__ENDIAN
+#include <sys/endian.h>
+#endif
+#endif /* _MACHINE_ENDIAN_H_ */
diff --git a/sys/arch/arm64/include/exec.h b/sys/arch/arm64/include/exec.h
new file mode 100644
index 00000000000..5d093d6d199
--- /dev/null
+++ b/sys/arch/arm64/include/exec.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: exec.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef _MACHINE_EXEC_H_
+#define _MACHINE_EXEC_H_
+
+#define __LDPGSZ 4096
+
+#define ARCH_ELFSIZE 64
+
+#define ELF_TARG_CLASS ELFCLASS64
+#define ELF_TARG_DATA ELFDATA2LSB
+#define ELF_TARG_MACH EM_AARCH64
+
+#define _NLIST_DO_ELF
+#define _KERN_DO_ELF64
+
+#endif
diff --git a/sys/arch/arm64/include/fdt.h b/sys/arch/arm64/include/fdt.h
new file mode 100644
index 00000000000..03949a49a8b
--- /dev/null
+++ b/sys/arch/arm64/include/fdt.h
@@ -0,0 +1,37 @@
+/* $OpenBSD: fdt.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#ifndef __ARM_FDT_H__
+#define __ARM_FDT_H__
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
+struct fdt_attach_args {
+ const char *fa_name;
+ int fa_node;
+ bus_space_tag_t fa_iot;
+ bus_dma_tag_t fa_dmat;
+ struct fdt_reg *fa_reg;
+ int fa_nreg;
+ uint32_t *fa_intr;
+ int fa_nintr;
+ int fa_acells;
+ int fa_scells;
+};
+
+#endif /* __ARM_FDT_H__ */
diff --git a/sys/arch/arm64/include/fenv.h b/sys/arch/arm64/include/fenv.h
new file mode 100644
index 00000000000..19bbcf573e7
--- /dev/null
+++ b/sys/arch/arm64/include/fenv.h
@@ -0,0 +1,120 @@
+/* $OpenBSD: fenv.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MACHINE_FENV_H_
+#define _MACHINE_FENV_H_
+
+/*
+ * Each symbol representing a floating point exception expands to an integer
+ * constant expression with values, such that bitwise-inclusive ORs of _all
+ * combinations_ of the constants result in distinct values.
+ *
+ * We use such values that allow direct bitwise operations on FPU registers.
+ */
+#define FE_INVALID 0x01
+#define FE_DIVBYZERO 0x02
+#define FE_OVERFLOW 0x04
+#define FE_UNDERFLOW 0x08
+#define FE_INEXACT 0x10
+#define FE_DENORMAL 0x80
+
+/*
+ * The following symbol is simply the bitwise-inclusive OR of all floating-point
+ * exception constants defined above.
+ */
+#ifdef __MACHINE_PCS_VFP
+#define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | \
+ FE_UNDERFLOW | FE_INEXACT | FE_DENORMAL)
+#else
+#define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | \
+ FE_UNDERFLOW | FE_INEXACT)
+#endif
+
+/*
+ * Each symbol representing the rounding direction, expands to an integer
+ * constant expression whose value is distinct non-negative value.
+ *
+ * We use such values that allow direct bitwise operations on FPU registers.
+ */
+
+#define VFP_FE_TONEAREST 0x00000000
+#define VFP_FE_UPWARD 0x00400000
+#define VFP_FE_DOWNWARD 0x00800000
+#define VFP_FE_TOWARDZERO 0x00c00000
+
+#ifdef __MACHINE_PCS_VFP
+#define FE_TONEAREST VFP_FE_TONEAREST
+#define FE_UPWARD VFP_FE_UPWARD
+#define FE_DOWNWARD VFP_FE_DOWNWARD
+#define FE_TOWARDZERO VFP_FE_TOWARDZERO
+#else
+#define FE_TONEAREST 0x0
+#define FE_UPWARD 0x1
+#define FE_DOWNWARD 0x2
+#define FE_TOWARDZERO 0x3
+#endif
+
+/*
+ * The following symbol is simply the bitwise-inclusive OR of all floating-point
+ * rounding direction constants defined above.
+ */
+#define _ROUND_MASK (FE_TONEAREST | FE_UPWARD | FE_DOWNWARD | \
+ FE_TOWARDZERO)
+
+/*
+ * fenv_t represents the entire floating-point environment.
+ */
+#ifdef __MACHINE_PCS_VFP
+typedef unsigned int fenv_t;
+#else
+typedef struct {
+ unsigned int __sticky;
+ unsigned int __mask;
+ unsigned int __round;
+} fenv_t;
+#endif
+
+/*
+ * The following constant represents the default floating-point environment
+ * (that is, the one installed at program startup) and has type pointer to
+ * const-qualified fenv_t.
+ *
+ * It can be used as an argument to the functions within the <fenv.h> header
+ * that manage the floating-point environment, namely fesetenv() and
+ * feupdateenv().
+ */
+__BEGIN_DECLS
+extern fenv_t __fe_dfl_env;
+__END_DECLS
+#define FE_DFL_ENV ((const fenv_t *)&__fe_dfl_env)
+
+/*
+ * fexcept_t represents the floating-point status flags collectively, including
+ * any status the implementation associates with the flags.
+ *
+ * A floating-point status flag is a system variable whose value is set (but
+ * never cleared) when a floating-point exception is raised, which occurs as a
+ * side effect of exceptional floating-point arithmetic to provide auxiliary
+ * information.
+ *
+ * A floating-point control mode is a system variable whose value may be set by
+ * the user to affect the subsequent behavior of floating-point arithmetic.
+ */
+typedef unsigned int fexcept_t;
+
+#endif /* !_MACHINE_FENV_H_ */
diff --git a/sys/arch/arm64/include/float.h b/sys/arch/arm64/include/float.h
new file mode 100644
index 00000000000..6d3ecbd0a37
--- /dev/null
+++ b/sys/arch/arm64/include/float.h
@@ -0,0 +1,97 @@
+/* $OpenBSD: float.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: float.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)float.h 8.1 (Berkeley) 6/11/93
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int __flt_rounds (void);
+__END_DECLS
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS __flt_rounds()
+#if __ISO_C_VISIBLE >= 1999
+#define FLT_EVAL_METHOD 0 /* no promotions */
+#endif
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-7F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP (-125) /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
+
+#if __ISO_C_VISIBLE >= 1999
+#define DECIMAL_DIG 17
+#endif
+
+#endif /* _MACHINE_FLOAT_H_ */
diff --git a/sys/arch/arm64/include/frame.h b/sys/arch/arm64/include/frame.h
new file mode 100644
index 00000000000..4ae1c4f7ec9
--- /dev/null
+++ b/sys/arch/arm64/include/frame.h
@@ -0,0 +1,74 @@
+/* $OpenBSD: frame.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MACHINE_FRAME_H_
+#define _MACHINE_FRAME_H_
+
+#ifndef _LOCORE
+
+#include <sys/signal.h>
+
+
+/*
+ * Exception/Trap Stack Frame
+ */
+#define clockframe trapframe
+typedef struct trapframe {
+ register_t tf_sp;
+ register_t tf_lr;
+ register_t tf_elr;
+ register_t tf_spsr;
+ register_t tf_x[30];
+} trapframe_t;
+
+/*
+ * pushed on stack for signal delivery
+ */
+struct sigframe {
+ int sf_signum;
+ struct sigcontext sf_sc;
+ siginfo_t sf_si;
+};
+
+/*
+ * System stack frames.
+ */
+
+/*
+ * Stack frame inside cpu_switch()
+ */
+
+struct switchframe {
+ register_t sf_x19;
+ register_t sf_x20;
+ register_t sf_x21;
+ register_t sf_x22;
+ register_t sf_x23;
+ register_t sf_x24;
+ register_t sf_x25;
+ register_t sf_x26;
+ register_t sf_x27;
+ register_t sf_x28;
+ register_t sf_x29;
+ register_t sf_lr;
+};
+
+#endif /* !_LOCORE */
+
+#endif /* _MACHINE_FRAME_H_ */
+
+/* End of frame.h */
diff --git a/sys/arch/arm64/include/hypervisor.h b/sys/arch/arm64/include/hypervisor.h
new file mode 100644
index 00000000000..2c51be0f54b
--- /dev/null
+++ b/sys/arch/arm64/include/hypervisor.h
@@ -0,0 +1,86 @@
+/* $OpenBSD: hypervisor.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2013, 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_HYPERVISOR_H_
+#define _MACHINE_HYPERVISOR_H_
+
+/*
+ * These registers are only useful when in hypervisor context,
+ * e.g. specific to EL2, or controlling the hypervisor.
+ */
+
+/*
+ * Architecture feature trap register
+ */
+#define CPTR_RES0 0x7fefc800
+#define CPTR_RES1 0x000033ff
+#define CPTR_TFP 0x00000400
+#define CPTR_TTA 0x00100000
+#define CPTR_TCPAC 0x80000000
+
+/*
+ * Hypervisor Config Register
+ */
+
+#define HCR_VM 0x0000000000000001
+#define HCR_SWIO 0x0000000000000002
+#define HCR_PTW 0x0000000000000004
+#define HCR_FMO 0x0000000000000008
+#define HCR_IMO 0x0000000000000010
+#define HCR_AMO 0x0000000000000020
+#define HCR_VF 0x0000000000000040
+#define HCR_VI 0x0000000000000080
+#define HCR_VSE 0x0000000000000100
+#define HCR_FB 0x0000000000000200
+#define HCR_BSU_MASK 0x0000000000000c00
+#define HCR_DC 0x0000000000001000
+#define HCR_TWI 0x0000000000002000
+#define HCR_TWE 0x0000000000004000
+#define HCR_TID0 0x0000000000008000
+#define HCR_TID1 0x0000000000010000
+#define HCR_TID2 0x0000000000020000
+#define HCR_TID3 0x0000000000040000
+#define HCR_TSC 0x0000000000080000
+#define HCR_TIDCP 0x0000000000100000
+#define HCR_TACR 0x0000000000200000
+#define HCR_TSW 0x0000000000400000
+#define HCR_TPC 0x0000000000800000
+#define HCR_TPU 0x0000000001000000
+#define HCR_TTLB 0x0000000002000000
+#define HCR_TVM 0x0000000004000000
+#define HCR_TGE 0x0000000008000000
+#define HCR_TDZ 0x0000000010000000
+#define HCR_HCD 0x0000000020000000
+#define HCR_TRVM 0x0000000040000000
+#define HCR_RW 0x0000000080000000
+#define HCR_CD 0x0000000100000000
+#define HCR_ID 0x0000000200000000
+
+#endif
+
diff --git a/sys/arch/arm64/include/ieee.h b/sys/arch/arm64/include/ieee.h
new file mode 100644
index 00000000000..a39beca4d63
--- /dev/null
+++ b/sys/arch/arm64/include/ieee.h
@@ -0,0 +1,149 @@
+/* $OpenBSD: ieee.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: ieee.h,v 1.1 1996/09/30 16:34:25 ws Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ieee.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * ieee.h defines the machine-dependent layout of the machine's IEEE
+ * floating point. It does *not* define (yet?) any of the rounding
+ * mode bits, exceptions, and so forth.
+ */
+
+/*
+ * Define the number of bits in each fraction and exponent.
+ *
+ * k k+1
+ * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented
+ *
+ * (-exp_bias+1)
+ * as fractions that look like 0.fffff x 2 . This means that
+ *
+ * -126
+ * the number 0.10000 x 2 , for instance, is the same as the normalized
+ *
+ * -127 -128
+ * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero
+ *
+ * -129
+ * in the fraction; to represent 2 , we need two, and so on. This
+ *
+ * (-exp_bias-fracbits+1)
+ * implies that the smallest denormalized number is 2
+ *
+ * for whichever format we are talking about: for single precision, for
+ *
+ * -126 -149
+ * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and
+ *
+ * -149 == -127 - 23 + 1.
+ */
+#define SNG_EXPBITS 8
+#define SNG_FRACBITS 23
+
+#define DBL_EXPBITS 11
+#define DBL_FRACHBITS 20
+#define DBL_FRACLBITS 32
+#define DBL_FRACBITS 52
+
+#define EXT_EXPBITS 15
+#define EXT_FRACHBITS 32
+#define EXT_FRACLBITS 32
+#define EXT_FRACBITS 64
+
+#define EXT_TO_ARRAY32(p, a) do { \
+ (a)[0] = (uint32_t)(p)->ext_fracl; \
+ (a)[1] = (uint32_t)(p)->ext_frach; \
+} while(0)
+
+struct ieee_single {
+ u_int sng_frac:23;
+ u_int sng_exp:8;
+ u_int sng_sign:1;
+};
+
+struct ieee_double {
+ u_int dbl_fracl;
+ u_int dbl_frach:20;
+ u_int dbl_exp:11;
+ u_int dbl_sign:1;
+};
+
+struct ieee_ldouble {
+ u_long ldbl_fracl;
+ u_long ldbl_frach:20;
+ u_int ldbl_exp:11;
+ u_int ldbl_sign:1;
+};
+
+struct ieee_ext {
+ u_int ext_fracl;
+ u_int ext_frach;
+ u_int ext_exp:15;
+ u_int ext_sign:1;
+ u_int ext_padl:16;
+ u_int ext_padh;
+};
+
+/*
+ * Floats whose exponent is in [1..INFNAN) (of whatever type) are
+ * `normal'. Floats whose exponent is INFNAN are either Inf or NaN.
+ * Floats whose exponent is zero are either zero (iff all fraction
+ * bits are zero) or subnormal values.
+ *
+ * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its
+ * high fraction; if the bit is set, it is a `quiet NaN'.
+ */
+#define SNG_EXP_INFNAN 255
+#define DBL_EXP_INFNAN 2047
+#define EXT_EXP_INFNAN 32767
+
+#if 0
+#define SNG_QUIETNAN (1 << 22)
+#define DBL_QUIETNAN (1 << 19)
+#define EXT_QUIETNAN (1 << 15)
+#endif
+
+/*
+ * Exponent biases.
+ */
+#define SNG_EXP_BIAS 127
+#define DBL_EXP_BIAS 1023
+#define EXT_EXP_BIAS 16383
diff --git a/sys/arch/arm64/include/ieeefp.h b/sys/arch/arm64/include/ieeefp.h
new file mode 100644
index 00000000000..9fe10db8779
--- /dev/null
+++ b/sys/arch/arm64/include/ieeefp.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: ieeefp.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: ieeefp.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */
+
+/*
+ * Based on ieeefp.h written by J.T. Conklin, Apr 28, 1995
+ * Public domain.
+ */
+
+#ifndef _MACHINE_IEEEFP_H_
+#define _MACHINE_IEEEFP_H_
+
+/* FP exception codes */
+
+#define FP_EXCEPT_INV 0
+#define FP_EXCEPT_DZ 1
+#define FP_EXCEPT_OFL 2
+#define FP_EXCEPT_UFL 3
+#define FP_EXCEPT_IMP 4
+
+/* Exception type (used by fpsetmask() et al.) */
+
+typedef int fp_except;
+
+/* Bit defines for fp_except */
+
+#define FP_X_INV (1 << FP_EXCEPT_INV) /* invalid operation exception */
+#define FP_X_DZ (1 << FP_EXCEPT_DZ) /* divide-by-zero exception */
+#define FP_X_OFL (1 << FP_EXCEPT_OFL) /* overflow exception */
+#define FP_X_UFL (1 << FP_EXCEPT_UFL) /* underflow exception */
+#define FP_X_IMP (1 << FP_EXCEPT_IMP) /* imprecise (loss of precision; "inexact") */
+
+/* Rounding modes */
+
+typedef enum {
+ FP_RN=0, /* round to nearest representable number */
+ FP_RP=1, /* round toward positive infinity */
+ FP_RM=2, /* round toward negative infinity */
+ FP_RZ=3 /* round to zero (truncate) */
+} fp_rnd;
+
+#endif /* _MACHINE_IEEEFP_H_ */
diff --git a/sys/arch/arm64/include/internal_types.h b/sys/arch/arm64/include/internal_types.h
new file mode 100644
index 00000000000..cf6d14f08c0
--- /dev/null
+++ b/sys/arch/arm64/include/internal_types.h
@@ -0,0 +1,10 @@
+/* $OpenBSD: internal_types.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* Public domain */
+#ifndef _MACHINE_INTERNAL_TYPES_H_
+#define _MACHINE_INTERNAL_TYPES_H_
+
+#ifdef __CHAR_UNSIGNED__
+#define __machine_has_unsigned_chars
+#endif
+
+#endif
diff --git a/sys/arch/arm64/include/intr.h b/sys/arch/arm64/include/intr.h
new file mode 100644
index 00000000000..10cbe793a93
--- /dev/null
+++ b/sys/arch/arm64/include/intr.h
@@ -0,0 +1,190 @@
+/* $OpenBSD: intr.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
+ *
+ * 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 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.
+ *
+ */
+
+#ifndef _MACHINE_INTR_H_
+#define _MACHINE_INTR_H_
+
+/*
+ * The interrupt level ipl is a logical level; per-platform interrupt
+ * code will turn it into the appropriate hardware interrupt masks
+ * values.
+ *
+ * Interrupt sources on the CPU are kept enabled regardless of the
+ * current ipl value; individual hardware sources interrupting while
+ * logically masked are masked on the fly, remembered as pending, and
+ * unmasked at the first splx() opportunity.
+ */
+#ifdef _KERNEL
+
+/* Interrupt priority `levels'; not mutually exclusive. */
+#define IPL_NONE 0 /* nothing */
+#define IPL_SOFT 1 /* soft interrupts */
+#define IPL_SOFTCLOCK 2 /* soft clock interrupts */
+#define IPL_SOFTNET 3 /* soft network interrupts */
+#define IPL_SOFTTTY 4 /* soft terminal interrupts */
+#define IPL_BIO 5 /* block I/O */
+#define IPL_NET 6 /* network */
+#define IPL_TTY 7 /* terminal */
+#define IPL_VM 8 /* memory allocation */
+#define IPL_AUDIO 9 /* audio */
+#define IPL_CLOCK 10 /* clock */
+#define IPL_SCHED IPL_CLOCK
+#define IPL_STATCLOCK IPL_CLOCK
+#define IPL_HIGH 11 /* everything */
+#define IPL_IPI 12 /* interprocessor interrupt */
+#define NIPL 13 /* number of levels */
+
+/* Interrupt priority 'flags'. */
+#define IPL_MPSAFE 0 /* no "mpsafe" interrupts */
+
+/* Interrupt sharing types. */
+#define IST_NONE 0 /* none */
+#define IST_PULSE 1 /* pulsed */
+#define IST_EDGE 2 /* edge-triggered */
+#define IST_LEVEL 3 /* level-triggered */
+
+#define IST_LEVEL_LOW IST_LEVEL
+#define IST_LEVEL_HIGH 4
+#define IST_EDGE_FALLING IST_EDGE
+#define IST_EDGE_RISING 5
+#define IST_EDGE_BOTH 6
+
+#ifndef _LOCORE
+#include <sys/device.h>
+#include <sys/queue.h>
+
+int splraise(int);
+int spllower(int);
+void splx(int);
+
+void arm_do_pending_intr(int);
+void arm_set_intr_handler(int (*raise)(int), int (*lower)(int),
+ void (*x)(int), void (*setipl)(int),
+ void *(*intr_establish)(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name),
+ void (*intr_disestablish)(void *cookie),
+ void (*intr_handle)(void *));
+
+struct arm_intr_func {
+ int (*raise)(int);
+ int (*lower)(int);
+ void (*x)(int);
+ void (*setipl)(int);
+ void *(*intr_establish)(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name);
+ void (*intr_disestablish)(void *cookie);
+};
+
+extern struct arm_intr_func arm_intr_func;
+
+#define splraise(cpl) (arm_intr_func.raise(cpl))
+#define _splraise(cpl) (arm_intr_func.raise(cpl))
+#define spllower(cpl) (arm_intr_func.lower(cpl))
+#define splx(cpl) (arm_intr_func.x(cpl))
+
+#define splsoft() splraise(IPL_SOFT)
+#define splsoftclock() splraise(IPL_SOFTCLOCK)
+#define splsoftnet() splraise(IPL_SOFTNET)
+#define splsofttty() splraise(IPL_SOFTTTY)
+#define splbio() splraise(IPL_BIO)
+#define splnet() splraise(IPL_NET)
+#define spltty() splraise(IPL_TTY)
+#define splvm() splraise(IPL_VM)
+#define splaudio() splraise(IPL_AUDIO)
+#define splclock() splraise(IPL_CLOCK)
+#define splsched() splraise(IPL_SCHED)
+#define splstatclock() splraise(IPL_STATCLOCK)
+#define splhigh() splraise(IPL_HIGH)
+
+#define spllock() splhigh()
+#define spl0() spllower(IPL_NONE)
+
+void intr_barrier(void *);
+
+void arm_init_smask(void); /* XXX */
+extern uint32_t arm_smask[NIPL];
+
+#include <machine/softintr.h>
+
+void *arm_intr_establish(int irqno, int level, int (*func)(void *),
+ void *cookie, char *name);
+void arm_intr_disestablish(void *cookie);
+
+/* XXX - this is probably the wrong location for this */
+void arm_clock_register(void (*)(void), void (*)(u_int), void (*)(int),
+ void (*)(void));
+
+struct interrupt_controller {
+ int ic_node;
+ void *ic_cookie;
+ void *(*ic_establish)(void *, int *, int, int (*)(void *),
+ void *, char *);
+ void (*ic_disestablish)(void *);
+
+ LIST_ENTRY(interrupt_controller) ic_list;
+ uint32_t ic_phandle;
+ uint32_t ic_cells;
+};
+
+void arm_intr_init_fdt(void);
+void arm_intr_register_fdt(struct interrupt_controller *);
+void *arm_intr_establish_fdt(int, int, int (*)(void *),
+ void *, char *);
+void *arm_intr_establish_fdt_idx(int, int, int, int (*)(void *),
+ void *, char *);
+void arm_intr_disestablish_fdt(void *);
+
+void *arm_intr_parent_establish_fdt(void *, int *, int,
+ int (*)(void *), void *, char *);
+void arm_intr_parent_disestablish_fdt(void *);
+
+#ifdef DIAGNOSTIC
+/*
+ * Although this function is implemented in MI code, it must be in this MD
+ * header because we don't want this header to include MI includes.
+ */
+void splassert_fail(int, int, const char *);
+extern int splassert_ctl;
+void arm_splassert_check(int, const char *);
+#define splassert(__wantipl) do { \
+ if (splassert_ctl > 0) { \
+ arm_splassert_check(__wantipl, __func__); \
+ } \
+} while (0)
+#define splsoftassert(wantipl) splassert(wantipl)
+#else
+#define splassert(wantipl) do { /* nothing */ } while (0)
+#define splsoftassert(wantipl) do { /* nothing */ } while (0)
+#endif
+
+#endif /* ! _LOCORE */
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_INTR_H_ */
+
diff --git a/sys/arch/arm64/include/kcore.h b/sys/arch/arm64/include/kcore.h
new file mode 100644
index 00000000000..65ebd4a913c
--- /dev/null
+++ b/sys/arch/arm64/include/kcore.h
@@ -0,0 +1,15 @@
+/* $OpenBSD: kcore.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* public domain */
+
+/* Make sure this is larger than DRAM_BLOCKS on all arm-based platforms */
+#define NPHYS_RAM_SEGS 8
+
+typedef struct cpu_kcore_hdr {
+ u_int64_t kernelbase; /* value of KERNEL_BASE */
+ u_int64_t kerneloffs; /* offset of kernel in RAM */
+ u_int64_t staticsize; /* size of contiguous mapping */
+ u_int64_t pmap_kernel_l1; /* pmap_kernel()->pm_l1 */
+ u_int64_t pmap_kernel_l2; /* pmap_kernel()->pm_l2 */
+ u_int64_t reserved[11];
+ phys_ram_seg_t ram_segs[NPHYS_RAM_SEGS];
+} cpu_kcore_hdr_t;
diff --git a/sys/arch/arm64/include/limits.h b/sys/arch/arm64/include/limits.h
new file mode 100644
index 00000000000..65ecb0e0634
--- /dev/null
+++ b/sys/arch/arm64/include/limits.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: limits.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: limits.h,v 1.4 2003/04/28 23:16:18 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 7.2 (Berkeley) 6/28/90
+ */
+
+#ifndef _MACHINE_LIMITS_H_
+#define _MACHINE_LIMITS_H_
+
+#include <sys/cdefs.h>
+
+#if __POSIX_VISIBLE || __XPG_VISIBLE
+#ifndef SIZE_MAX
+#define SIZE_MAX ULONG_MAX /* max value for a size_t */
+#endif
+#define SSIZE_MAX LONG_MAX /* max value for a ssize_t */
+#endif
+
+#if __BSD_VISIBLE
+#define SIZE_T_MAX ULONG_MAX /* max value for a size_t (historic) */
+
+#define UQUAD_MAX 0xffffffffffffffffULL /* max unsigned quad */
+#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
+#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
+
+#endif /* __BSD_VISIBLE */
+
+#endif /* _MACHINE_LIMITS_H_ */
diff --git a/sys/arch/arm64/include/loadfile_machdep.h b/sys/arch/arm64/include/loadfile_machdep.h
new file mode 100644
index 00000000000..0226bce5b84
--- /dev/null
+++ b/sys/arch/arm64/include/loadfile_machdep.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: loadfile_machdep.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: loadfile_machdep.h,v 1.1 1999/04/29 03:17:12 tsubai Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define BOOT_ELF
+#define ELFSIZE 64
+
+#define LOAD_KERNEL (LOAD_ALL & ~LOAD_TEXTA)
+#define COUNT_KERNEL (COUNT_ALL & ~COUNT_TEXTA)
+
+extern u_long efi_loadaddr;
+#define LOADADDR(a) (((((u_long)(a)) + offset)&0x7fffffffff) + \
+ efi_loadaddr)
+#define ALIGNENTRY(a) ((u_long)(a))
+#define READ(f, b, c) read((f), (void *)LOADADDR(b), (c))
+#define BCOPY(s, d, c) memcpy((void *)LOADADDR(d), (void *)(s), (c))
+#define BZERO(d, c) memset((void *)LOADADDR(d), 0, (c))
+#define WARN(a) (void)(printf a, \
+ printf((errno ? ": %s\n" : "\n"), \
+ strerror(errno)))
+#define PROGRESS(a) (void) printf a
+#define ALLOC(a) alloc(a)
+#define FREE(a, b) free(a, b)
+
+void run_loadfile(u_long *, int);
diff --git a/sys/arch/arm64/include/lock.h b/sys/arch/arm64/include/lock.h
new file mode 100644
index 00000000000..35510e3abdb
--- /dev/null
+++ b/sys/arch/arm64/include/lock.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: lock.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+/*
+ * Machine-dependent spin lock operations.
+ */
+
+#ifndef _MACHINE_LOCK_H_
+#define _MACHINE_LOCK_H_
+
+#include <machine/atomic.h>
+
+typedef __volatile int __cpu_simple_lock_t;
+
+#define __SIMPLELOCK_LOCKED 1
+#define __SIMPLELOCK_UNLOCKED 0
+
+#endif /* _MACHINE_LOCK_H_ */
diff --git a/sys/arch/arm64/include/machdep.h b/sys/arch/arm64/include/machdep.h
new file mode 100644
index 00000000000..db9d729ec4c
--- /dev/null
+++ b/sys/arch/arm64/include/machdep.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: machdep.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: machdep.h,v 1.7 2002/02/21 02:52:21 thorpej Exp $ */
+
+#ifndef _MACHINE_MACHDEP_H_
+#define _MACHINE_MACHDEP_H_
+
+/* misc prototypes used by the many arm machdeps */
+void halt (void);
+void parse_mi_bootargs (char *);
+void data_abort_handler (trapframe_t *);
+void prefetch_abort_handler (trapframe_t *);
+void undefinedinstruction_bounce (trapframe_t *);
+void dumpsys (void);
+
+/*
+ * note that we use void * as all the platforms have different ideas on what
+ * the structure is
+ */
+u_int initarm (void *, void *, void *);
+
+/* from arm/arm/intr.c */
+void dosoftints (void);
+void set_spl_masks (void);
+#ifdef DIAGNOSTIC
+void dump_spl_masks (void);
+#endif
+#endif
diff --git a/sys/arch/arm64/include/machine_reg.h b/sys/arch/arm64/include/machine_reg.h
new file mode 100644
index 00000000000..033d6603cdc
--- /dev/null
+++ b/sys/arch/arm64/include/machine_reg.h
@@ -0,0 +1,57 @@
+/* $OpenBSD: machine_reg.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * 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. The name of Genetec Corporation may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION
+ * 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.
+ */
+
+
+#ifndef _MACHINE_REG_H
+#define _MACHINE_REG_H
+
+/*
+ * Logical mapping for onboard/integrated peripherals
+ */
+#define MACHINE_IO_AREA_VBASE 0xfd000000
+#define MACHINE_GPIO_VBASE 0xfd000000
+#define MACHINE_CLKMAN_VBASE 0xfd100000
+#define MACHINE_INTCTL_VBASE 0xfd200000
+#define MACHINE_AGPIO_VBASE 0xfd300000
+#define MACHINE_VBASE_FREE 0xfd400000
+/* FFUART and/or BTUART are mapped to this area when
+ used for console or kgdb port */
+
+#define ioreg_read(a) (*(volatile unsigned *)(a))
+#define ioreg_write(a,v) (*(volatile unsigned *)(a)=(v))
+
+#define ioreg16_read(a) (*(volatile uint16_t *)(a))
+#define ioreg16_write(a,v) (*(volatile uint16_t *)(a)=(v))
+
+#define ioreg8_read(a) (*(volatile uint8_t *)(a))
+#define ioreg8_write(a,v) (*(volatile uint8_t *)(a)=(v))
+
+#endif /* _MACHINE_REG_H */
diff --git a/sys/arch/arm64/include/mplock.h b/sys/arch/arm64/include/mplock.h
new file mode 100644
index 00000000000..f85c6df27d8
--- /dev/null
+++ b/sys/arch/arm64/include/mplock.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: mplock.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2004 Niklas Hallqvist. 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 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.
+ */
+
+#ifndef _MACHINE_MPLOCK_H_
+#define _MACHINE_MPLOCK_H_
+
+struct __mp_lock_cpu {
+ u_int mplc_ticket;
+ u_int mplc_depth;
+};
+
+struct __mp_lock {
+ struct __mp_lock_cpu mpl_cpus[MAXCPUS];
+ atomic_int mpl_ticket;
+ atomic_int mpl_users;
+};
+
+#ifndef _LOCORE
+
+void __mp_lock_init(struct __mp_lock *);
+void __mp_lock(struct __mp_lock *);
+void __mp_unlock(struct __mp_lock *);
+int __mp_release_all(struct __mp_lock *);
+int __mp_release_all_but_one(struct __mp_lock *);
+void __mp_acquire_count(struct __mp_lock *, int);
+int __mp_lock_held(struct __mp_lock *);
+
+#endif
+
+#endif /* !_MACHINE_MPLOCK_H */
diff --git a/sys/arch/arm64/include/mutex.h b/sys/arch/arm64/include/mutex.h
new file mode 100644
index 00000000000..1cad62e8b4e
--- /dev/null
+++ b/sys/arch/arm64/include/mutex.h
@@ -0,0 +1,67 @@
+/* $OpenBSD: mutex.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2004 Artur Grabowski <art@openbsd.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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
+#ifndef _MACHINE_MUTEX_H_
+#define _MACHINE_MUTEX_H_
+
+struct mutex {
+ int mtx_wantipl;
+ int mtx_oldipl;
+ volatile void *mtx_owner;
+};
+
+/*
+ * To prevent lock ordering problems with the kernel lock, we need to
+ * make sure we block all interrupts that can grab the kernel lock.
+ * The simplest way to achieve this is to make sure mutexes always
+ * raise the interrupt priority level to the highest level that has
+ * interrupts that grab the kernel lock.
+ */
+#ifdef MULTIPROCESSOR
+#define __MUTEX_IPL(ipl) \
+ (((ipl) > IPL_NONE && (ipl) < IPL_TTY) ? IPL_TTY : (ipl))
+#else
+#define __MUTEX_IPL(ipl) (ipl)
+#endif
+
+#define MUTEX_INITIALIZER(ipl) { __MUTEX_IPL((ipl)), 0, NULL }
+
+void __mtx_init(struct mutex *, int);
+#define mtx_init(mtx, ipl) __mtx_init((mtx), __MUTEX_IPL((ipl)))
+
+#define MUTEX_ASSERT_LOCKED(mtx) do { \
+ if ((mtx)->mtx_owner != curcpu()) \
+ panic("mutex %p not held in %s", (mtx), __func__); \
+} while (0)
+
+#define MUTEX_ASSERT_UNLOCKED(mtx) do { \
+ if ((mtx)->mtx_owner == curcpu()) \
+ panic("mutex %p held in %s", (mtx), __func__); \
+} while (0)
+
+#define MUTEX_OLDIPL(mtx) (mtx)->mtx_oldipl
+
+#endif
diff --git a/sys/arch/arm64/include/param.h b/sys/arch/arm64/include/param.h
new file mode 100644
index 00000000000..9d6b5f93a78
--- /dev/null
+++ b/sys/arch/arm64/include/param.h
@@ -0,0 +1,84 @@
+/* $OpenBSD: param.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MACHINE_PARAM_H_
+#define _MACHINE_PARAM_H_
+
+#ifdef _KERNEL
+#include <machine/cpu.h>
+#endif
+
+#define _MACHINE arm64
+#define MACHINE "arm64"
+#define _MACHINE_ARCH aarch64
+#define MACHINE_ARCH "aarch64"
+#define MID_MACHINE MID_ARM64
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1LL << PAGE_SHIFT)
+#define PAGE_MASK ((vaddr_t)PAGE_SIZE - 1)
+
+#define KERNBASE 0xffffff8000000000ULL /* start of kernel virtual space */
+
+#ifdef _KERNEL
+
+//#define KERNBASE_HI 0xffffffff
+//#define KERNBASE_LO 0x80000000
+
+#define NBPG PAGE_SIZE /* bytes/page */
+#define PGSHIFT PAGE_SHIFT /* LOG2(PAGE_SIZE) */
+#define PGOFSET PAGE_MASK /* byte offset into page */
+
+#define UPAGES 5 /* pages of u-area */
+#define USPACE (UPAGES * PAGE_SIZE) /* total size of u-area */
+#define USPACE_ALIGN 0 /* u-area alignment 0-none */
+
+#define NMBCLUSTERS 4096 /* map size, max cluster allocation */
+
+#ifndef MSGBUFSIZE
+#define MSGBUFSIZE (16 * PAGE_SIZE) /* default message buffer size */
+#endif
+
+/*
+ * Maximum size of the kernel malloc arena in PAGE_SIZE-sized
+ * logical pages.
+ */
+#define NKMEMPAGES_MAX_DEFAULT ((128 * 1024 * 1024) >> PAGE_SHIFT)
+
+#define STACKALIGNBYTES (16 - 1)
+#define STACKALIGN(p) ((u_long)(p) &~ STACKALIGNBYTES)
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_PARAM_H_ */
diff --git a/sys/arch/arm64/include/pcb.h b/sys/arch/arm64/include/pcb.h
new file mode 100644
index 00000000000..e62cc36f828
--- /dev/null
+++ b/sys/arch/arm64/include/pcb.h
@@ -0,0 +1,45 @@
+/* $OpenBSD: pcb.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _MACHINE_PCB_H_
+#define _MACHINE_PCB_H_
+
+#include <machine/frame.h>
+
+#include <machine/pte.h>
+#include <machine/reg.h>
+
+struct trapframe;
+
+/*
+ * Warning certain fields must be within 256 bytes of the beginning
+ * of this structure.
+ */
+struct pcb {
+ u_int pcb_flags;
+#define PCB_FPU 0x00000001 /* Process had FPU initialized */
+ struct trapframe *pcb_tf;
+
+ register_t pcb_sp; // stack pointer of switchframe
+
+ caddr_t pcb_onfault; // On fault handler
+ struct fpreg pcb_fpstate; // Floating Point state */
+ struct cpu_info *pcb_fpcpu;
+ paddr_t pcb_pagedir; // ttbr0
+
+ uint64_t pcb_tcb;
+};
+#endif /* _MACHINE_PCB_H_ */
diff --git a/sys/arch/arm64/include/pmap.h b/sys/arch/arm64/include/pmap.h
new file mode 100644
index 00000000000..4f0044cd65a
--- /dev/null
+++ b/sys/arch/arm64/include/pmap.h
@@ -0,0 +1,138 @@
+/* $OpenBSD: pmap.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2008,2009,2014 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _ARM64_PMAP_H_
+#define _ARM64_PMAP_H_
+
+#include <arm64/pte.h>
+
+#define PMAP_PA_MASK ~((paddr_t)PAGE_MASK) /* to remove the flags */
+
+typedef struct pmap *pmap_t;
+
+/* V->P mapping data */
+#define VP_IDX0_CNT 512
+#define VP_IDX0_MASK (VP_IDX0_CNT-1)
+#define VP_IDX0_POS 39
+#define VP_IDX1_CNT 512
+#define VP_IDX1_MASK (VP_IDX1_CNT-1)
+#define VP_IDX1_POS 30
+#define VP_IDX2_CNT 512
+#define VP_IDX2_MASK (VP_IDX2_CNT-1)
+#define VP_IDX2_POS 21
+#define VP_IDX3_CNT 512
+#define VP_IDX3_MASK (VP_IDX3_CNT-1)
+#define VP_IDX3_POS 12
+
+void pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable);
+/* cache flags */
+#define PMAP_CACHE_DEFAULT 0 /* WB cache managed mem, devices not */
+#define PMAP_CACHE_CI (PMAP_MD0) /* cache inhibit */
+#define PMAP_CACHE_WT (PMAP_MD1) /* writethru */
+#define PMAP_CACHE_WB (PMAP_MD1|PMAP_MD0) /* writeback */
+#define PMAP_CACHE_PTE (PMAP_MD2) /* PTE mapping */
+#define PMAP_CACHE_DEV (PMAP_MD2|PMAP_MD0) /* device mapping */
+#define PMAP_CACHE_BITS (PMAP_MD0|PMAP_MD1|PMAP_MD2)
+
+#define PTED_VA_MANAGED_M (PMAP_MD3)
+#define PTED_VA_WIRED_M (PMAP_MD3 << 1)
+#define PTED_VA_EXEC_M (PMAP_MD3 << 2)
+
+#define PG_PMAP_MOD PG_PMAP0
+#define PG_PMAP_REF PG_PMAP1
+#define PG_PMAP_EXE PG_PMAP2
+
+// [NCPUS]
+extern paddr_t zero_page;
+extern paddr_t copy_src_page;
+extern paddr_t copy_dst_page;
+
+/*
+ * Pmap stuff
+ */
+struct pmap {
+ union {
+ struct pmapvp0 *l0; /* virtual to physical table 4 lvl */
+ struct pmapvp1 *l1; /* virtual to physical table 3 lvl */
+ } pm_vp;
+ uint64_t pm_pt0pa;
+ int have_4_level_pt;
+ int pm_asid;
+ int pm_active;
+ int pm_refs; /* ref count */
+ struct pmap_statistics pm_stats; /* pmap statistics */
+};
+
+
+extern struct pmap kernel_pmap_;
+#define pmap_kernel() (&kernel_pmap_)
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count)
+
+vaddr_t pmap_bootstrap(long kvo, paddr_t lpt1, long kernelstart,
+ long kernelend, long ram_start, long ram_end);
+void pmap_page_ro(pmap_t pm, vaddr_t va, vm_prot_t prot);
+
+void pmap_avail_fixup();
+void pmap_physload_avail();
+
+struct pv_entry;
+
+/* investigate */
+#define pmap_unuse_final(p) do { /* nothing */ } while (0)
+int pmap_fault_fixup(pmap_t, vaddr_t, vm_prot_t, int);
+void pmap_postinit(void);
+void pmap_map_section(vaddr_t, vaddr_t, paddr_t, int, int);
+void pmap_map_entry(vaddr_t, vaddr_t, paddr_t, int, int);
+vsize_t pmap_map_chunk(vaddr_t, vaddr_t, paddr_t, vsize_t, int, int);
+
+/*
+ * Physical / virtual address structure. In a number of places (particularly
+ * during bootstrapping) we need to keep track of the physical and virtual
+ * addresses of various pages
+ */
+typedef struct pv_addr {
+ SLIST_ENTRY(pv_addr) pv_list;
+ paddr_t pv_pa;
+ vaddr_t pv_va;
+} pv_addr_t;
+void vector_page_setprot(int);
+
+#define PTE_NOCACHE 0
+#define PTE_CACHE 1
+#define PTE_PAGETABLE 2
+
+vsize_t pmap_map_chunk(vaddr_t, vaddr_t, paddr_t, vsize_t, int, int);
+void pmap_link_l2pt(vaddr_t, vaddr_t, pv_addr_t *);
+
+extern vaddr_t pmap_curmaxkvaddr;
+
+#ifndef _LOCORE
+
+#define __HAVE_VM_PAGE_MD
+struct vm_page_md {
+ LIST_HEAD(,pte_desc) pv_list;
+ int pvh_attrs; /* page attributes */
+};
+
+#define VM_MDPAGE_INIT(pg) do { \
+ LIST_INIT(&((pg)->mdpage.pv_list)); \
+ (pg)->mdpage.pvh_attrs = 0; \
+} while (0)
+
+#endif /* _LOCORE */
+
+#endif /* _ARM64_PMAP_H_ */
diff --git a/sys/arch/arm64/include/proc.h b/sys/arch/arm64/include/proc.h
new file mode 100644
index 00000000000..178a85c8e1d
--- /dev/null
+++ b/sys/arch/arm64/include/proc.h
@@ -0,0 +1,47 @@
+/* $OpenBSD: proc.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: proc.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */
+
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)proc.h 7.1 (Berkeley) 5/15/91
+ */
+
+#ifndef _MACHINE_PROC_H_
+#define _MACHINE_PROC_H_
+
+/*
+ * Machine-dependent part of the proc structure for arm64.
+ */
+struct mdproc {
+ volatile int md_astpending;
+};
+
+#define __HAVE_MD_TCB
+
+#endif /* _MACHINE_PROC_H_ */
diff --git a/sys/arch/arm64/include/profile.h b/sys/arch/arm64/include/profile.h
new file mode 100644
index 00000000000..4e7d32336a1
--- /dev/null
+++ b/sys/arch/arm64/include/profile.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: profile.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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.
+ */
+
+#define _MCOUNT_DECL void _mcount
+
+#define MCOUNT_ASM_NAME "__mcount"
+
+#ifdef __PIC__
+#define PLTSYM "" /* XXX -aarch64 defaults to PLT? */
+#else
+#define PLTSYM ""
+#endif
+
+#define MCOUNT \
+__asm__ (".text;" \
+ ".align 3;" \
+ ".globl " MCOUNT_ASM_NAME ";" \
+ ".type " MCOUNT_ASM_NAME ",@function;" \
+ MCOUNT_ASM_NAME ":;" \
+ " stp x0, x1, [sp, #-160]!;" \
+ " stp x2, x3, [sp, #16];" \
+ " stp x4, x5, [sp, #32];" \
+ " stp x6, x7, [sp, #48];" \
+ " stp x8, x9, [sp, #64];" \
+ " stp x10,x11,[sp, #80];" \
+ " stp x12,x13,[sp, #96];" \
+ " stp x14,x15,[sp, #112];" \
+ " stp x16,x17,[sp, #128];" \
+ " stp x29,lr, [sp, #144];" \
+ /* load from pc at 8 off frame pointer */ \
+ " ldr x0, [x29, #8];" \
+ " mov x1, lr;" \
+ " bl " __STRING(_mcount) PLTSYM ";" \
+ /* restore argument registers */ \
+ " ldp x2, x3, [sp, #16];" \
+ " ldp x4, x5, [sp, #32];" \
+ " ldp x6, x7, [sp, #48];" \
+ " ldp x8, x9, [sp, #64];" \
+ " ldp x10,x11,[sp, #80];" \
+ " ldp x12,x13,[sp, #96];" \
+ " ldp x14,x15,[sp, #112];" \
+ " ldp x16,x17,[sp, #128];" \
+ " ldp x29,lr, [sp, #144];" \
+ " ldp x0, x1, [sp], #160;" \
+ " ret;");
+
+#ifdef _KERNEL
+// Change this to dair read/set, then restore.
+#define MCOUNT_ENTER \
+__asm__ ("mrs %x0,daif; msr daifset, #0x2": "=r"(s));
+#define MCOUNT_EXIT \
+__asm__ ("msr daif, %x0":: "r"(s));
+
+#endif // _KERNEL
diff --git a/sys/arch/arm64/include/pte.h b/sys/arch/arm64/include/pte.h
new file mode 100644
index 00000000000..05b3d067a7d
--- /dev/null
+++ b/sys/arch/arm64/include/pte.h
@@ -0,0 +1,130 @@
+/* $OpenBSD: pte.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _ARM_PTE_H_
+#define _ARM_PTE_H_
+
+#include "arm64/vmparam.h"
+
+/* level X descriptor */
+#define Lx_TYPE_MASK (0x00000003) /* mask of type bits */
+#define Lx_TYPE_S (0x00000001)
+#define Lx_TYPE_PT (0x00000003)
+// XXX need to investigate use of these
+#define Lx_PT_NS (1ULL<<63)
+#define Lx_PT_AP00 (0ULL<<61)
+#define Lx_PT_AP01 (1ULL<<61)
+#define Lx_PT_AP10 (2ULL<<61)
+#define Lx_PT_AP11 (3ULL<<61)
+#define Lx_PT_XN (1ULL<<60)
+#define Lx_PT_PXN (1ULL<<59)
+#define Lx_TABLE_ALIGN (4096)
+
+/* Block and Page attributes */
+/* TODO: Add the upper attributes */
+#define ATTR_MASK_H (0xfff0000000000000ULL)
+#define ATTR_MASK_L (0x0000000000000fffULL)
+#define ATTR_MASK (ATTR_MASK_H | ATTR_MASK_L)
+/* Bits 58:55 are reserved for software */
+#define ATTR_SW_MANAGED (1UL << 56)
+#define ATTR_SW_WIRED (1UL << 55)
+#define ATTR_UXN (1UL << 54)
+#define ATTR_PXN (1UL << 53)
+#define ATTR_nG (1 << 11)
+#define ATTR_AF (1 << 10)
+#define ATTR_SH(x) ((x) << 8)
+#define ATTR_AP_RW_BIT (1 << 7)
+#define ATTR_AP(x) ((x) << 6)
+#define ATTR_AP_MASK ATTR_AP(3)
+#define ATTR_NS (1 << 5)
+#define ATTR_IDX(x) ((x) << 2)
+#define ATTR_IDX_MASK (7 << 2)
+
+#define PTE_ATTR_DEV 0
+#define PTE_ATTR_CI 1
+#define PTE_ATTR_WB 2
+
+
+#define SH_INNER 3
+#define SH_OUTER 2
+#define SH_NONE 0
+
+/* Level 0 table, 512GiB per entry */
+#define L0_SHIFT 39
+#define L0_INVAL 0x0 /* An invalid address */
+#define L0_BLOCK 0x1 /* A block */
+ /* 0x2 also marks an invalid address */
+#define L0_TABLE 0x3 /* A next-level table */
+
+
+/* Level 1 table, 1GiB per entry */
+#define L1_SHIFT 30
+#define L1_SIZE (1 << L1_SHIFT)
+#define L1_OFFSET (L1_SIZE - 1)
+#define L1_INVAL L0_INVAL
+#define L1_BLOCK L0_BLOCK
+#define L1_TABLE L0_TABLE
+
+/* Level 2 table, 2MiB per entry */
+#define L2_SHIFT 21
+#define L2_SIZE (1 << L2_SHIFT)
+//#define L2_OFFSET L2_SIZE - 1)
+//#define L2_INVAL L0_INVAL
+#define L2_BLOCK L0_BLOCK
+//#define L2_TABLE L0_TABLE
+
+#define L2_SHIFT 21
+#define L2_SIZE (1 << L2_SHIFT)
+
+// page mapping
+#define L3_P (3)
+
+#define Ln_ENTRIES (1 << 9)
+#define Ln_ADDR_MASK (Ln_ENTRIES - 1)
+#define Ln_TABLE_MASK ((1 << 12) - 1)
+
+/* physical page mask */
+#define PTE_RPGN 0x3ffffff000ULL
+
+/* XXX */
+#ifndef _LOCORE
+struct pte {
+ uint64_t pte;
+};
+
+typedef uint64_t pd_entry_t; /* L1 table entry */
+typedef uint64_t pt_entry_t; /* L2 table entry */
+
+struct pv_node {
+};
+
+#endif /* _LOCORE */
+
+
+/// REWRITE
+#define L2_L_SIZE 0x00010000 /* 64K */
+#define L2_L_OFFSET (L2_L_SIZE - 1)
+#define L2_L_FRAME (~L2_L_OFFSET)
+#define L2_L_SHIFT 16
+
+#define L2_S_SIZE 0x00001000 /* 4K */
+#define L2_S_OFFSET (L2_S_SIZE - 1)
+#define L2_S_FRAME (~L2_S_OFFSET)
+#define L2_S_SHIFT 12
+
+///
+
+#endif /* _ARM_PTE_H_ */
diff --git a/sys/arch/arm64/include/ptrace.h b/sys/arch/arm64/include/ptrace.h
new file mode 100644
index 00000000000..a5ca9476618
--- /dev/null
+++ b/sys/arch/arm64/include/ptrace.h
@@ -0,0 +1,22 @@
+/* $OpenBSD: ptrace.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#define PT_STEP (PT_FIRSTMACH + 0)
+#define PT_GETREGS (PT_FIRSTMACH + 1)
+#define PT_SETREGS (PT_FIRSTMACH + 2)
+#define PT_GETFPREGS (PT_FIRSTMACH + 3)
+#define PT_SETFPREGS (PT_FIRSTMACH + 4)
diff --git a/sys/arch/arm64/include/reg.h b/sys/arch/arm64/include/reg.h
new file mode 100644
index 00000000000..ac431b864e6
--- /dev/null
+++ b/sys/arch/arm64/include/reg.h
@@ -0,0 +1,35 @@
+/* $OpenBSD: reg.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef _MACHINE_REG_H_
+#define _MACHINE_REG_H_
+
+struct reg {
+ unsigned long x[30];
+ unsigned long x_sp;
+ unsigned long x_lr;
+ unsigned long x_pc;
+ unsigned long x_cpsr;
+};
+
+struct fpreg {
+ uint64_t fp_registers[64]; // really 32 128 bit registers.
+ uint32_t fp_sr;
+ uint32_t fp_cr;
+};
+
+#endif /* !_MACHINE_REG_H_ */
diff --git a/sys/arch/arm64/include/reloc.h b/sys/arch/arm64/include/reloc.h
new file mode 100644
index 00000000000..bff8653f52b
--- /dev/null
+++ b/sys/arch/arm64/include/reloc.h
@@ -0,0 +1,126 @@
+/* $OpenBSD: reloc.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * AArch64 static relocation types.
+ */
+
+/* Miscellaneous. */
+#define R_ARM_NONE 0
+#define R_AARCH64_TPOFF64 1 /// COMPLETELY WRONG - stub
+#define R_AARCH64_NONE 256
+
+/* Data. */
+#define R_AARCH64_ABS64 257
+#define R_AARCH64_ABS32 258
+#define R_AARCH64_ABS16 259
+#define R_AARCH64_PREL64 260
+#define R_AARCH64_PREL32 261
+#define R_AARCH64_PREL16 262
+
+/* Instructions. */
+#define R_AARCH64_MOVW_UABS_G0 263
+#define R_AARCH64_MOVW_UABS_G0_NC 264
+#define R_AARCH64_MOVW_UABS_G1 265
+#define R_AARCH64_MOVW_UABS_G1_NC 266
+#define R_AARCH64_MOVW_UABS_G2 267
+#define R_AARCH64_MOVW_UABS_G2_NC 268
+#define R_AARCH64_MOVW_UABS_G3 269
+
+#define R_AARCH64_MOVW_SABS_G0 270
+#define R_AARCH64_MOVW_SABS_G1 271
+#define R_AARCH64_MOVW_SABS_G2 272
+
+#define R_AARCH64_LD_PREL_LO19 273
+#define R_AARCH64_ADR_PREL_LO21 274
+#define R_AARCH64_ADR_PREL_PG_HI21 275
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276
+#define R_AARCH64_ADD_ABS_LO12_NC 277
+#define R_AARCH64_LDST8_ABS_LO12_NC 278
+
+#define R_AARCH64_TSTBR14 279
+#define R_AARCH64_CONDBR19 280
+#define R_AARCH64_JUMP26 282
+#define R_AARCH64_CALL26 283
+#define R_AARCH64_LDST16_ABS_LO12_NC 284
+#define R_AARCH64_LDST32_ABS_LO12_NC 285
+#define R_AARCH64_LDST64_ABS_LO12_NC 286
+#define R_AARCH64_LDST128_ABS_LO12_NC 299
+
+#define R_AARCH64_MOVW_PREL_G0 287
+#define R_AARCH64_MOVW_PREL_G0_NC 288
+#define R_AARCH64_MOVW_PREL_G1 289
+#define R_AARCH64_MOVW_PREL_G1_NC 290
+#define R_AARCH64_MOVW_PREL_G2 291
+#define R_AARCH64_MOVW_PREL_G2_NC 292
+#define R_AARCH64_MOVW_PREL_G3 293
+
+
+#define R_AARCH64_COPY 1024
+#define R_AARCH64_GLOB_DAT 1025 // S + A
+#define R_AARCH64_JUMP_SLOT 1026 // S + A
+#define R_AARCH64_RELATIVE 1027 // Delta(S) + A
+#define R_AARCH64_TLS_DTPREL64 1028 // DTPREL(S+A)
+#define R_AARCH64_TLS_DTPMOD64 1029 // LDM(S)
+#define R_AARCH64_TLS_TPREL64 1030 // TPREL(S+A)
+#define R_AARCH64_TLSDESC 1031 // TLSDESC(S+A) TLS descriptor to be filled
+#define R_AARCH64_IRELATIVE 1032 // Indirect(Delta(S) + A)
+
+// old arm32 defines.
+/* Processor specific relocation types */
+
+#define R_ARM_NONE 0
+#define R_ARM_PC24 1
+#define R_ARM_ABS32 2
+#define R_ARM_REL32 3
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5
+#define R_ARM_ABS12 6
+#define R_ARM_THM_ABS5 7
+#define R_ARM_ABS8 8
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10
+#define R_ARM_THM_PC8 11
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13
+#define R_ARM_THM_SWI8 14
+#define R_ARM_XPC25 15
+#define R_ARM_THM_XPC22 16
+
+/* 17-31 are reserved for ARM Linux. */
+#define R_ARM_TLS_DTPMOD32 17
+#define R_ARM_TLS_DTPOFF32 18
+#define R_ARM_TLS_TPOFF32 19
+
+#define R_ARM_COPY 20
+#define R_ARM_GLOB_DAT 21
+#define R_ARM_JUMP_SLOT 22
+#define R_ARM_RELATIVE 23
+#define R_ARM_GOTOFF 24
+#define R_ARM_GOTPC 25
+#define R_ARM_GOT32 26
+#define R_ARM_PLT32 27
+
+#define R_ARM_ALU_PCREL_7_0 32
+#define R_ARM_ALU_PCREL_15_8 33
+#define R_ARM_ALU_PCREL_23_15 34
+#define R_ARM_ALU_SBREL_11_0 35
+#define R_ARM_ALU_SBREL_19_12 36
+#define R_ARM_ALU_SBREL_27_20 37
+
+/* 96-111 are reserved to G++. */
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_THM_PC11 102
+#define R_ARM_THM_PC9 103
+
+/* 112-127 are reserved for private experiments. */
+
+#define R_ARM_RXPC25 249
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS32 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+
+
+
diff --git a/sys/arch/arm64/include/setjmp.h b/sys/arch/arm64/include/setjmp.h
new file mode 100644
index 00000000000..ffc83289c0a
--- /dev/null
+++ b/sys/arch/arm64/include/setjmp.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: setjmp.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: setjmp.h,v 1.2 2001/08/25 14:45:59 bjh21 Exp $ */
+
+/*
+ * machine/setjmp.h: machine dependent setjmp-related information.
+ */
+
+#define _JBLEN 64 /* size, in longs, of a jmp_buf */
+
+/*
+ * NOTE: The internal structure of a jmp_buf is *PRIVATE*
+ * This information is provided as there is software
+ * that fiddles with this with obtain the stack pointer
+ * (yes really ! and it's commercial !).
+ *
+ * Description of the setjmp buffer
+ *
+ * word 0 magic number (dependant on creator)
+ * 1 - 3 f4 fp register 4
+ * 4 - 6 f5 fp register 5
+ * 7 - 9 f6 fp register 6
+ * 10 - 12 f7 fp register 7
+ * 13 fpsr fp status register
+ * 14 r4 register 4
+ * 15 r5 register 5
+ * 16 r6 register 6
+ * 17 r7 register 7
+ * 18 r8 register 8
+ * 19 r9 register 9
+ * 20 r10 register 10 (sl)
+ * 21 r11 register 11 (fp)
+ * 22 r12 register 12 (ip)
+ * 23 r13 register 13 (sp)
+ * 24 r14 register 14 (lr)
+ * 25 signal mask (dependant on magic)
+ * 26 (con't)
+ * 27 (con't)
+ * 28 (con't)
+ *
+ * The magic number number identifies the jmp_buf and
+ * how the buffer was created as well as providing
+ * a sanity check.
+ *
+ * A side note I should mention - please do not tamper
+ * with the floating point fields. While they are
+ * always saved and restored at the moment this cannot
+ * be guaranteed especially if the compiler happens
+ * to be generating soft-float code so no fp
+ * registers will be used.
+ *
+ * Whilst this can be seen an encouraging people to
+ * use the setjmp buffer in this way I think that it
+ * is for the best then if changes occur compiles will
+ * break rather than just having new builds falling over
+ * mysteriously.
+ */
+
+#define _JB_MAGIC__SETJMP 0x4278f500
+#define _JB_MAGIC_SETJMP 0x4278f501
+
+/* Valid for all jmp_buf's */
+
+#define _JB_MAGIC 0
+#define _JB_REG_F4 1
+#define _JB_REG_F5 4
+#define _JB_REG_F6 7
+#define _JB_REG_F7 10
+#define _JB_REG_FPSR 13
+#define _JB_REG_R4 14
+#define _JB_REG_R5 15
+#define _JB_REG_R6 16
+#define _JB_REG_R7 17
+#define _JB_REG_R8 18
+#define _JB_REG_R9 19
+#define _JB_REG_R10 20
+#define _JB_REG_R11 21
+#define _JB_REG_R12 22
+#define _JB_REG_R13 23
+#define _JB_REG_R14 24
+
+/* Only valid with the _JB_MAGIC_SETJMP magic */
+
+#define _JB_SIGMASK 25
diff --git a/sys/arch/arm64/include/signal.h b/sys/arch/arm64/include/signal.h
new file mode 100644
index 00000000000..ebe453bc7b1
--- /dev/null
+++ b/sys/arch/arm64/include/signal.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: signal.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)signal.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _MACHINE_SIGNAL_H_
+#define _MACHINE_SIGNAL_H_
+
+#include <sys/cdefs.h>
+
+#if !defined(__LANGUAGE_ASSEMBLY)
+#include <sys/types.h>
+
+/*
+ * Machine-dependent signal definitions
+ */
+typedef int sig_atomic_t;
+
+#if __BSD_VISIBLE || __XPG_VISIBLE >= 420
+/*
+ * Information pushed on stack when a signal is delivered.
+ * This is used by the kernel to restore state following
+ * execution of the signal handler. It is also made available
+ * to the handler to allow it to restore state properly if
+ * a non-standard exit is performed.
+ */
+struct sigcontext {
+ int __sc_unused;
+ int sc_mask; /* signal mask to restore (old style) */
+
+ uint64_t sc_sp;
+ uint64_t sc_lr;
+ uint64_t sc_elr;
+ uint64_t sc_spsr;
+ uint64_t sc_x[30];
+};
+#endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */
+
+#endif /* !__LANGUAGE_ASSEMBLY */
+
+#endif /* !_MACHINE_SIGNAL_H_ */
diff --git a/sys/arch/arm64/include/softintr.h b/sys/arch/arm64/include/softintr.h
new file mode 100644
index 00000000000..8b2e005bf9e
--- /dev/null
+++ b/sys/arch/arm64/include/softintr.h
@@ -0,0 +1,100 @@
+/* $OpenBSD: softintr.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: softintr.h,v 1.1 2002/01/29 22:54:14 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum, and by Jason R. Thorpe.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _MACHINE_SOFTINTR_H_
+#define _MACHINE_SOFTINTR_H_
+
+#ifdef _KERNEL
+
+#include <sys/mutex.h>
+#include <sys/queue.h>
+
+/*
+ * Generic software interrupt support for all AArch64 platforms.
+ *
+ * To use this code, include <machine/softintr.h> from your platform's
+ * <machine/intr.h>.
+ */
+
+#define SIR_SOFT 0 /* for IPL_SOFT */
+#define SIR_CLOCK 1 /* for IPL_SOFTCLOCK */
+#define SIR_NET 2 /* for IPL_SOFTNET */
+#define SIR_TTY 3 /* for IPL_SOFTTTY */
+
+#define SI_NSOFTINTR 4
+
+struct soft_intrhand {
+ TAILQ_ENTRY(soft_intrhand)
+ sih_q;
+ struct soft_intr *sih_intrhead;
+ void (*sih_fn)(void *);
+ void (*sih_fnwrap)(void *);
+ void *sih_arg;
+ void *sih_argwrap;
+ int sih_pending;
+};
+
+struct soft_intr {
+ TAILQ_HEAD(, soft_intrhand)
+ softintr_q;
+ int softintr_ssir;
+ struct mutex softintr_lock;
+};
+
+#define SOFTINTR_ESTABLISH_MPSAFE 0x01
+void *softintr_establish_flags(int, void (*)(void *), void *, int);
+#define softintr_establish(i, f, a) \
+ softintr_establish_flags(i, f, a, 0)
+#define softintr_establish_mpsafe(i, f, a) \
+ softintr_establish_flags(i, f, a, SOFTINTR_ESTABLISH_MPSAFE)
+void softintr_disestablish(void *);
+void softintr_init(void);
+void softintr_dispatch(int);
+void softintr(int);
+
+#define softintr_schedule(arg) \
+do { \
+ struct soft_intrhand *__sih = (arg); \
+ struct soft_intr *__si = __sih->sih_intrhead; \
+ \
+ mtx_enter(&__si->softintr_lock); \
+ if (__sih->sih_pending == 0) { \
+ TAILQ_INSERT_TAIL(&__si->softintr_q, __sih, sih_q); \
+ __sih->sih_pending = 1; \
+ softintr(__si->softintr_ssir); \
+ } \
+ mtx_leave(&__si->softintr_lock); \
+} while (/*CONSTCOND*/ 0)
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_SOFTINTR_H_ */
diff --git a/sys/arch/arm64/include/spinlock.h b/sys/arch/arm64/include/spinlock.h
new file mode 100644
index 00000000000..7a55e4831d0
--- /dev/null
+++ b/sys/arch/arm64/include/spinlock.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: spinlock.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef _MACHINE_SPINLOCK_H_
+#define _MACHINE_SPINLOCK_H_
+
+#define _ATOMIC_LOCK_UNLOCKED (0)
+#define _ATOMIC_LOCK_LOCKED (1)
+typedef int _atomic_lock_t;
+
+#ifndef _KERNEL
+int _atomic_lock(volatile _atomic_lock_t *);
+#endif
+
+#endif
diff --git a/sys/arch/arm64/include/stdarg.h b/sys/arch/arm64/include/stdarg.h
new file mode 100644
index 00000000000..cbe800f8439
--- /dev/null
+++ b/sys/arch/arm64/include/stdarg.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: stdarg.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: stdarg.h,v 1.7 2003/08/07 16:26:53 agc Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdarg.h 8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _MACHINE_STDARG_H_
+#define _MACHINE_STDARG_H_
+
+#include <sys/cdefs.h>
+#include <machine/_types.h>
+
+typedef __va_list va_list;
+#ifdef __lint__
+#define __builtin_next_arg(t) ((t) ? 0 : 0)
+#define __builtin_stdarg_start(a, l) ((a) = ((l) ? 0 : 0))
+#define __builtin_va_arg(a, t) ((a) ? 0 : 0)
+#define __builtin_va_end /* nothing */
+#define __builtin_va_copy(d, s) ((d) = (s))
+#endif
+
+#define va_start(ap, last) __builtin_stdarg_start((ap), (last))
+
+#define va_arg(ap, type) __builtin_va_arg((ap), type)
+#define va_end(ap) __builtin_va_end((ap))
+#define __va_copy(dest, src) __builtin_va_copy((dest), (src))
+
+#endif /* !_MACHINE_STDARG_H_ */
diff --git a/sys/arch/arm64/include/swi.h b/sys/arch/arm64/include/swi.h
new file mode 100644
index 00000000000..85cedd5e15c
--- /dev/null
+++ b/sys/arch/arm64/include/swi.h
@@ -0,0 +1,23 @@
+/* $OpenBSD: swi.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: swi.h,v 1.1 2002/01/13 15:03:06 bjh21 Exp $ */
+
+/*
+ * This file is in the Public Domain.
+ * Ben Harris, 2002.
+ */
+
+#ifndef _MACHINE_SWI_H_
+#define _MACHINE_SWI_H_
+
+#define SWI_OS_MASK 0xf00000
+#define SWI_OS_RISCOS 0x000000
+#define SWI_OS_RISCIX 0x800000
+#define SWI_OS_LINUX 0x900000
+#define SWI_OS_NETBSD 0xa00000
+#define SWI_OS_ARM 0xf00000
+
+#define SWI_IMB 0xf00000
+#define SWI_IMBrange 0xf00001
+
+#endif
+
diff --git a/sys/arch/arm64/include/sysarch.h b/sys/arch/arm64/include/sysarch.h
new file mode 100644
index 00000000000..1b169314184
--- /dev/null
+++ b/sys/arch/arm64/include/sysarch.h
@@ -0,0 +1,21 @@
+/* $OpenBSD: sysarch.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _MACHINE_SYSARCH_H_
+
+// aarch64 architecture has no libarch or arch specific syscalls.
+
+#endif /* !_MACHINE_SYSARCH_H_ */
diff --git a/sys/arch/arm64/include/tcb.h b/sys/arch/arm64/include/tcb.h
new file mode 100644
index 00000000000..1870c4cdf07
--- /dev/null
+++ b/sys/arch/arm64/include/tcb.h
@@ -0,0 +1,60 @@
+/* $OpenBSD: tcb.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2011 Philip Guenther <guenther@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MACHINE_TCB_H_
+#define _MACHINE_TCB_H_
+
+#ifdef _KERNEL
+
+#include <machine/pcb.h>
+
+static inline void
+__aarch64_set_tcb(uint64_t tcb) {
+ __asm volatile("msr tpidr_el0, %x0" :: "r" (tcb));
+ return ;
+}
+#define TCB_GET(p) \
+ ((void *)((struct pcb *)(p)->p_addr)->pcb_tcb)
+#define TCB_SET(p, addr) \
+ do { \
+ (((struct pcb *)(p)->p_addr)->pcb_tcb = (uint64_t)(addr)); \
+ __aarch64_set_tcb((uint64_t)addr); \
+ } while (0)
+
+#else /* _KERNEL */
+
+/* ELF TLS ABI calls for small TCB, with static TLS data after it */
+#define TLS_VARIANT 1
+
+static inline uint64_t
+__aarch64_read_tcb(void) {
+ uint64_t tcb;
+ __asm volatile("mrs %x0, tpidr_el0": "=r" (tcb));
+
+ return tcb;
+}
+
+#define TCB_GET(p) \
+ ((void *)__aarch64_read_tcb())
+
+#define TCB_GET_MEMBER(member) \
+ (((struct thread_control_block *)__aarch64_read_tcb())->member)
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_TCB_H_ */
diff --git a/sys/arch/arm64/include/trap.h b/sys/arch/arm64/include/trap.h
new file mode 100644
index 00000000000..0e9e595589c
--- /dev/null
+++ b/sys/arch/arm64/include/trap.h
@@ -0,0 +1,22 @@
+/* $OpenBSD: trap.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
+ *
+ * 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.
+ */
+
+#define KERNEL_BREAKPOINT 0x42000000 /* Used by DDB */
+
+#define KBPT_ASM "brk #0"
+
+#define USER_BREAKPOINT 0x42000000
diff --git a/sys/arch/arm64/include/vfp.h b/sys/arch/arm64/include/vfp.h
new file mode 100644
index 00000000000..f6240aab92f
--- /dev/null
+++ b/sys/arch/arm64/include/vfp.h
@@ -0,0 +1,47 @@
+/* $OpenBSD: vfp.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+ * Copyright (c) 2012 Mark Tinguely
+ *
+ * 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$
+ */
+
+
+#ifndef _MACHINE__VFP_H_
+#define _MACHINE__VFP_H_
+
+#ifdef _KERNEL
+/* Only kernel defines exist here */
+
+#define VFP_KFPEN (1 << 20)
+#define VFP_UFPEN (3 << 20)
+
+void vfp_init(void);
+void vfp_discard(struct proc *p);
+void vfp_save(void);
+void vfp_enable(void);
+int vfp_fault(vaddr_t pc, uint32_t insn, trapframe_t *tf, int fault_code);
+
+#endif /* _KERNEL */
+#endif /* _MACHINE__VFP_H_ */
diff --git a/sys/arch/arm64/include/vmparam.h b/sys/arch/arm64/include/vmparam.h
new file mode 100644
index 00000000000..2bb7aaf4ac9
--- /dev/null
+++ b/sys/arch/arm64/include/vmparam.h
@@ -0,0 +1,112 @@
+/* $OpenBSD: vmparam.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $NetBSD: vmparam.h,v 1.1 2003/04/26 18:39:49 fvdl Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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 the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vmparam.h 5.9 (Berkeley) 5/12/91
+ */
+
+#ifndef _MACHINE_VMPARAM_H_
+#define _MACHINE_VMPARAM_H_
+
+/*
+ * Machine dependent constants for arm64.
+ */
+
+#define USRSTACK VM_MAXUSER_ADDRESS
+
+/*
+ * Virtual memory related constants, all in bytes
+ */
+#define MAXTSIZ ((paddr_t)256*1024*1024) /* max text size */
+#ifndef DFLDSIZ
+#define DFLDSIZ ((paddr_t)512*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ ((paddr_t)16*1024*1024*1024) /* max data size */
+#endif
+#ifndef BRKSIZ
+#define BRKSIZ ((paddr_t)16*1024*1024*1024) /* heap gap size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ ((paddr_t)2*1024*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ ((paddr_t)8*1024*1024) /* max stack size */
+#endif
+
+#define STACKGAP_RANDOM 256*1024
+
+/*
+ * Size of shared memory map
+ */
+#ifndef SHMMAXPGS
+#define SHMMAXPGS 1024
+#endif
+
+/*
+ * Size of User Raw I/O map
+ */
+#define USRIOSIZE 300
+
+/*
+ * Page sizes
+ */
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1LL << PAGE_SHIFT)
+#define PAGE_MASK ((vaddr_t)PAGE_SIZE - 1)
+
+/*
+ * Kernel base
+ */
+#define KERNEL_BASE 0xffffff8000000000ULL
+
+/*
+ * Mach derived constants
+ */
+
+/* user/kernel map constants */
+#define VM_MIN_ADDRESS ((vaddr_t)PAGE_SIZE)
+#define USER_SPACE_BITS 38
+#define VM_MAXUSER_ADDRESS ((1ULL << USER_SPACE_BITS) - 0x8000)
+#define VM_MAX_ADDRESS VM_MAXUSER_ADDRESS
+#define VM_MIN_KERNEL_ADDRESS ((vaddr_t)0xffffff8000000000ULL)
+#define VM_MAX_KERNEL_ADDRESS ((vaddr_t)0xffffff804fffffffULL)
+
+/* virtual sizes (bytes) for various kernel submaps */
+#define VM_PHYS_SIZE (USRIOSIZE*PAGE_SIZE)
+
+#define VM_PHYSSEG_MAX 2
+#define VM_PHYSSEG_STRAT VM_PSTRAT_RANDOM
+#define VM_PHYSSEG_NOADD /* can't add RAM after vm_mem_init */
+
+#endif /* _MACHINE_VMPARAM_H_ */
diff --git a/sys/arch/arm64/stand/Makefile b/sys/arch/arm64/stand/Makefile
new file mode 100644
index 00000000000..dd9427dd538
--- /dev/null
+++ b/sys/arch/arm64/stand/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD: Makefile,v 1.1 2016/12/17 23:38:33 patrick Exp $
+
+SUBDIR= efiboot
+
+.include <bsd.subdir.mk>
diff --git a/sys/arch/arm64/stand/efiboot/Makefile b/sys/arch/arm64/stand/efiboot/Makefile
new file mode 100644
index 00000000000..6b0c6284d33
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/Makefile
@@ -0,0 +1,78 @@
+# $OpenBSD: Makefile,v 1.1 2016/12/17 23:38:33 patrick Exp $
+
+NOMAN= #
+
+.if ${MACHINE} == "arm64"
+
+PROG= BOOTAA64.EFI
+OBJFMT= binary
+INSTALL_STRIP=
+BINDIR= /usr/mdec
+SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efidev.c fdt.c
+
+S= ${.CURDIR}/../../../..
+EFIDIR= ${S}/stand/efi
+
+OBJCOPY?= objcopy
+OBJDUMP?= objdump
+
+LDFLAGS+=-nostdlib -T ${.CURDIR}/ldscript.arm64 -Bsymbolic -shared
+
+.PATH: ${S}/stand/boot
+SRCS+= boot.c cmd.c vars.c
+
+.PATH: ${S}/lib/libsa
+SRCS+= alloc.c ctime.c exit.c getchar.c memcmp.o memcpy.o memmove.c memset.c \
+ printf.c putchar.c snprintf.c strchr.c strcmp.c strerror.c strncmp.c \
+ strncpy.c strtol.c
+SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c fstat.c \
+ lseek.c open.c read.c readdir.c stat.c
+SRCS+= loadfile.c
+SRCS+= ufs.c
+
+.PATH: ${S}/lib/libkern/arch/arm64 ${S}/lib/libkern
+SRCS+= divdi3.c moddi3.c qdivrem.c strlcpy.c strlen.c
+
+.PATH: ${S}/lib/libz
+SRCS+= adler32.c crc32.c inflate.c inftrees.c
+
+CPPFLAGS+= -nostdinc
+CPPFLAGS+= -I${S} -I. -I${.CURDIR}
+CPPFLAGS+= -I${EFIDIR}/include -I${EFIDIR}/include/arm64
+CPPFLAGS+= -D_STANDALONE
+CPPFLAGS+= -DSMALL -DSLOW -DNOBYFOUR -D__INTERNAL_LIBSA_CREAD
+CPPFLAGS+= -DNEEDS_HEAP_H
+COPTS+= -Wno-attributes -Wno-format
+COPTS+= -ffreestanding -fno-stack-protector
+COPTS+= -fshort-wchar -fPIC -fno-builtin
+COPTS+= -Wall -Werror
+
+PROG.elf= ${PROG:S/.EFI/.elf/}
+CLEANFILES+= ${PROG.elf} ${PROG.elf}.tmp
+
+${PROG}: ${PROG.elf}
+ ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \
+ -j .dynamic -j .dynsym -j .dynstr -j .rel -j .rel.dyn \
+ -j .rela -j .rela.dyn -j .reloc \
+ --output-target=${OBJFMT} ${PROG.elf} ${.TARGET}
+
+.include <bsd.prog.mk>
+
+${PROG.elf}: ${OBJS}
+ ${LD} ${LDFLAGS} -o ${.TARGET}.tmp ${OBJS} ${LDADD}
+ @if ${OBJDUMP} -t ${.TARGET}.tmp | grep 'UND'; then \
+ (echo Undefined symbols; false); \
+ fi
+ mv ${.TARGET}.tmp ${.TARGET}
+
+.if !make(clean) && !make(cleandir) && !make(includes) && !make(obj)
+.BEGIN:
+ @([ -h machine ] || ln -s ${.CURDIR}/../../../${MACHINE}/include machine)
+.NOPATH: machine
+CLEANFILES+= machine
+.endif
+
+.else
+NOPROG=yes
+.include <bsd.prog.mk>
+.endif
diff --git a/sys/arch/arm64/stand/efiboot/conf.c b/sys/arch/arm64/stand/efiboot/conf.c
new file mode 100644
index 00000000000..45b4d4c517a
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/conf.c
@@ -0,0 +1,56 @@
+/* $OpenBSD: conf.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <lib/libsa/stand.h>
+#include <lib/libsa/ufs.h>
+#include <dev/cons.h>
+
+#include "efiboot.h"
+#include "efidev.h"
+
+const char version[] = "0.1";
+int debug = 0;
+
+struct fs_ops file_system[] = {
+ { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
+ ufs_stat, ufs_readdir },
+};
+int nfsys = nitems(file_system);
+
+struct devsw devsw[] = {
+ { "sd", efistrategy, efiopen, eficlose, efiioctl },
+};
+int ndevs = nitems(devsw);
+
+struct consdev constab[] = {
+ { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc },
+ { NULL }
+};
+struct consdev *cn_tab;
diff --git a/sys/arch/arm64/stand/efiboot/disk.h b/sys/arch/arm64/stand/efiboot/disk.h
new file mode 100644
index 00000000000..4007259da32
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/disk.h
@@ -0,0 +1,20 @@
+/* $OpenBSD: disk.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+#ifndef _DISK_H
+#define _DISK_H
+
+typedef struct efi_diskinfo {
+ EFI_BLOCK_IO *blkio;
+ UINT32 mediaid;
+} *efi_diskinfo_t;
+
+struct diskinfo {
+ struct efi_diskinfo ed;
+ struct disklabel disklabel;
+
+ u_int sc_part;
+};
+
+extern struct diskinfo diskinfo;
+
+#endif /* _DISK_H */
diff --git a/sys/arch/arm64/stand/efiboot/efiboot.c b/sys/arch/arm64/stand/efiboot/efiboot.c
new file mode 100644
index 00000000000..cdb01af68f0
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/efiboot.c
@@ -0,0 +1,527 @@
+/* $OpenBSD: efiboot.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ * Copyright (c) 2016 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <dev/cons.h>
+#include <sys/disklabel.h>
+
+#include <efi.h>
+#include <efiapi.h>
+#include <efiprot.h>
+#include <eficonsctl.h>
+
+#include <lib/libkern/libkern.h>
+#include <stand/boot/cmd.h>
+
+#include "disk.h"
+#include "eficall.h"
+#include "fdt.h"
+#include "libsa.h"
+
+EFI_SYSTEM_TABLE *ST;
+EFI_BOOT_SERVICES *BS;
+EFI_RUNTIME_SERVICES *RS;
+EFI_HANDLE IH;
+
+EFI_HANDLE efi_bootdp;
+
+static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL;
+static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
+static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
+
+static void efi_timer_init(void);
+static void efi_timer_cleanup(void);
+static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
+
+EFI_STATUS
+efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
+{
+ extern char *progname;
+ EFI_LOADED_IMAGE *imgp;
+ EFI_DEVICE_PATH *dp = NULL;
+ EFI_STATUS status;
+
+ ST = systab;
+ BS = ST->BootServices;
+ IH = image;
+
+ status = EFI_CALL(BS->HandleProtocol, image, &imgp_guid,
+ (void **)&imgp);
+ if (status == EFI_SUCCESS)
+ status = EFI_CALL(BS->HandleProtocol, imgp->DeviceHandle,
+ &devp_guid, (void **)&dp);
+ if (status == EFI_SUCCESS)
+ efi_bootdp = dp;
+
+ progname = "BOOTAA64";
+
+ boot(0);
+
+ return (EFI_SUCCESS);
+}
+
+static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
+static SIMPLE_INPUT_INTERFACE *conin;
+
+void
+efi_cons_probe(struct consdev *cn)
+{
+ cn->cn_pri = CN_MIDPRI;
+ cn->cn_dev = makedev(12, 0);
+}
+
+void
+efi_cons_init(struct consdev *cp)
+{
+ conin = ST->ConIn;
+ conout = ST->ConOut;
+}
+
+int
+efi_cons_getc(dev_t dev)
+{
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+#if 0
+ UINTN dummy;
+#endif
+ static int lastchar = 0;
+
+ if (lastchar) {
+ int r = lastchar;
+ if ((dev & 0x80) == 0)
+ lastchar = 0;
+ return (r);
+ }
+
+ status = conin->ReadKeyStroke(conin, &key);
+ while (status == EFI_NOT_READY) {
+ if (dev & 0x80)
+ return (0);
+ /*
+ * XXX The implementation of WaitForEvent() in U-boot
+ * is broken and neverreturns.
+ */
+#if 0
+ BS->WaitForEvent(1, &conin->WaitForKey, &dummy);
+#endif
+ status = conin->ReadKeyStroke(conin, &key);
+ }
+
+ if (dev & 0x80)
+ lastchar = key.UnicodeChar;
+
+ return (key.UnicodeChar);
+}
+
+void
+efi_cons_putc(dev_t dev, int c)
+{
+ CHAR16 buf[2];
+
+ if (c == '\n')
+ efi_cons_putc(dev, '\r');
+
+ buf[0] = c;
+ buf[1] = 0;
+
+ conout->OutputString(conout, buf);
+}
+
+EFI_PHYSICAL_ADDRESS heap;
+UINTN heapsiz = 1 * 1024 * 1024;
+
+static void
+efi_heap_init(void)
+{
+ EFI_STATUS status;
+
+ status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(heapsiz), &heap);
+ if (status != EFI_SUCCESS)
+ panic("BS->AllocatePages()");
+}
+
+EFI_BLOCK_IO *disk;
+
+void
+efi_diskprobe(void)
+{
+ int i, bootdev;
+ UINTN sz;
+ EFI_STATUS status;
+ EFI_HANDLE *handles = NULL;
+ EFI_BLOCK_IO *blkio;
+ EFI_BLOCK_IO_MEDIA *media;
+ EFI_DEVICE_PATH *dp, *bp;
+
+ sz = 0;
+ status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 0, &sz, 0);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ handles = alloc(sz);
+ status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid,
+ 0, &sz, handles);
+ }
+ if (handles == NULL || EFI_ERROR(status))
+ panic("BS->LocateHandle() returns %d", status);
+
+ for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
+ bootdev = 0;
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &blkio_guid,
+ (void **)&blkio);
+ if (EFI_ERROR(status))
+ panic("BS->HandleProtocol() returns %d", status);
+
+ media = blkio->Media;
+ if (media->LogicalPartition || !media->MediaPresent)
+ continue;
+
+ if (efi_bootdp == NULL)
+ goto next;
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
+ (void **)&dp);
+ if (EFI_ERROR(status))
+ goto next;
+ bp = efi_bootdp;
+ while (1) {
+ if (IsDevicePathEnd(dp)) {
+ bootdev = 1;
+ break;
+ }
+ if (memcmp(dp, bp, sizeof(EFI_DEVICE_PATH)) != 0 ||
+ memcmp(dp, bp, DevicePathNodeLength(dp)) != 0)
+ break;
+ dp = NextDevicePathNode(dp);
+ bp = NextDevicePathNode(bp);
+ }
+next:
+ if (bootdev) {
+ disk = blkio;
+ break;
+ }
+ }
+
+ free(handles, sz);
+}
+
+static EFI_GUID fdt_guid = FDT_TABLE_GUID;
+
+#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
+
+void *
+efi_makebootargs(char *bootargs)
+{
+ void *fdt = NULL;
+ char bootduid[8];
+ u_char zero[8];
+ void *node;
+ size_t len;
+ int i;
+
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ if (efi_guidcmp(&fdt_guid,
+ &ST->ConfigurationTable[i].VendorGuid) == 0)
+ fdt = ST->ConfigurationTable[i].VendorTable;
+ }
+
+ if (!fdt_init(fdt))
+ return NULL;
+
+ node = fdt_find_node("/chosen");
+ if (!node)
+ return NULL;
+
+ len = strlen(bootargs) + 1;
+ fdt_node_add_property(node, "bootargs", bootargs, len);
+
+ /* Pass DUID of the boot disk. */
+ memset(&zero, 0, sizeof(zero));
+ memcpy(&bootduid, diskinfo.disklabel.d_uid, sizeof(bootduid));
+ if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
+ fdt_node_add_property(node, "openbsd,bootduid", bootduid,
+ sizeof(bootduid));
+ }
+
+ fdt_finalize();
+
+ return fdt;
+}
+
+u_long efi_loadaddr;
+
+void
+machdep(void)
+{
+ EFI_PHYSICAL_ADDRESS addr;
+
+ cninit();
+ efi_heap_init();
+
+ /*
+ * The kernel expects to be loaded at offset 0x00200000 into a
+ * block of memory aligned on a 256MB boundary. We allocate a
+ * block of 32MB of memory, which gives us plenty of room for
+ * growth.
+ */
+ if (efi_memprobe_find(EFI_SIZE_TO_PAGES(32 * 1024 * 1024),
+ 0x10000000, &addr) != EFI_SUCCESS)
+ printf("Can't allocate memory\n");
+ efi_loadaddr = addr;
+
+ efi_timer_init();
+ efi_diskprobe();
+}
+
+void
+efi_cleanup(void)
+{
+ efi_timer_cleanup();
+
+ BS->ExitBootServices(NULL, 0);
+}
+
+void
+_rtt(void)
+{
+#ifdef EFI_DEBUG
+ printf("Hit any key to reboot\n");
+ efi_cons_getc(0);
+#endif
+ /*
+ * XXX ResetSystem doesn't seem to work on U-Boot 2016.05 on
+ * the CuBox-i. So trigger an unimplemented instruction trap
+ * instead.
+ */
+#if 1
+ asm volatile(".word 0xa000f7f0\n");
+#else
+ RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
+#endif
+ while (1) { }
+}
+
+/*
+ * U-Boot only implements the GetTime() Runtime Service if it has been
+ * configured with CONFIG_DM_RTC. Most board configurations don't
+ * include that option, so we can't use it to implement our boot
+ * prompt timeout. Instead we use timer events to simulate a clock
+ * that ticks ever second.
+ */
+
+EFI_EVENT timer;
+int ticks;
+
+static VOID
+efi_timer(EFI_EVENT event, VOID *context)
+{
+ ticks++;
+}
+
+static void
+efi_timer_init(void)
+{
+ EFI_STATUS status;
+
+ status = BS->CreateEvent(EVT_TIMER, TPL_CALLBACK,
+ efi_timer, NULL, &timer);
+ if (status == EFI_SUCCESS)
+ status = BS->SetTimer(timer, TimerPeriodic, 10000000);
+ if (EFI_ERROR(status))
+ printf("Can't create timer\n");
+}
+
+static void
+efi_timer_cleanup(void)
+{
+ BS->CloseEvent(timer);
+}
+
+time_t
+getsecs(void)
+{
+ return ticks;
+}
+
+/*
+ * Various device-related bits.
+ */
+
+void
+devboot(dev_t dev, char *p)
+{
+ strlcpy(p, "sd0a", 5);
+}
+
+int
+cnspeed(dev_t dev, int sp)
+{
+ return 115200;
+}
+
+char *
+ttyname(int fd)
+{
+ return "com0";
+}
+
+dev_t
+ttydev(char *name)
+{
+ return NODEV;
+}
+
+#define MAXDEVNAME 16
+
+/*
+ * Parse a device spec.
+ *
+ * [A-Za-z]*[0-9]*[A-Za-z]:file
+ * dev uint part
+ */
+int
+devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
+{
+ const char *s;
+
+ *unit = 0; /* default to wd0a */
+ *part = 0;
+ *dev = 0;
+
+ s = strchr(fname, ':');
+ if (s != NULL) {
+ int devlen;
+ int i, u, p = 0;
+ struct devsw *dp;
+ char devname[MAXDEVNAME];
+
+ devlen = s - fname;
+ if (devlen > MAXDEVNAME)
+ return (EINVAL);
+
+ /* extract device name */
+ for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
+ devname[i] = fname[i];
+ devname[i] = 0;
+
+ if (!isdigit(fname[i]))
+ return (EUNIT);
+
+ /* device number */
+ for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
+ u = u * 10 + (fname[i] - '0');
+
+ if (!isalpha(fname[i]))
+ return (EPART);
+
+ /* partition number */
+ if (i < devlen)
+ p = fname[i++] - 'a';
+
+ if (i != devlen)
+ return (ENXIO);
+
+ /* check device name */
+ for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
+ if (dp->dv_name && !strcmp(devname, dp->dv_name))
+ break;
+ }
+
+ if (i >= ndevs)
+ return (ENXIO);
+
+ *unit = u;
+ *part = p;
+ *dev = i;
+ fname = ++s;
+ }
+
+ *file = fname;
+
+ return (0);
+}
+
+int
+devopen(struct open_file *f, const char *fname, char **file)
+{
+ struct devsw *dp;
+ int dev, unit, part, error;
+
+ error = devparse(fname, &dev, &unit, &part, (const char **)file);
+ if (error)
+ return (error);
+
+ dp = &devsw[0];
+ f->f_dev = dp;
+
+ return (*dp->dv_open)(f, unit, part);
+}
+
+/*
+ * 64-bit ARMs can have a much wider memory mapping, as in somewhere
+ * after the 32-bit region. To cope with our alignment requirement,
+ * use the memory table to find a place where we can fit.
+ */
+static EFI_STATUS
+efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
+{
+ EFI_STATUS status;
+ UINTN mapkey, mmsiz, siz;
+ UINT32 mmver;
+ EFI_MEMORY_DESCRIPTOR *mm0, *mm;
+ int i, j, n;
+
+ if (align < EFI_PAGE_SIZE)
+ return EFI_INVALID_PARAMETER;
+
+ 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;
+
+ for (i = 0, mm = mm0; i < n; i++, mm = NextMemoryDescriptor(mm, mmsiz)) {
+ if (mm->Type != EfiConventionalMemory)
+ continue;
+
+ if (mm->NumberOfPages < pages)
+ continue;
+
+ for (j = 0; j < mm->NumberOfPages; i++) {
+ EFI_PHYSICAL_ADDRESS paddr;
+
+ if (mm->NumberOfPages - j < pages)
+ break;
+
+ paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE);
+ if (!(paddr & (align - 1))) {
+ *addr = paddr;
+ free(mm0, siz);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ free(mm0, siz);
+ return EFI_OUT_OF_RESOURCES;
+}
diff --git a/sys/arch/arm64/stand/efiboot/efiboot.h b/sys/arch/arm64/stand/efiboot/efiboot.h
new file mode 100644
index 00000000000..87d92558d10
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/efiboot.h
@@ -0,0 +1,25 @@
+/* $OpenBSD: efiboot.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void efi_cleanup(void);
+void efi_diskprobe(void);
+void *efi_makebootargs(char *);
+void efi_cons_probe(struct consdev *);
+void efi_cons_init(struct consdev *);
+int efi_cons_getc(dev_t);
+void efi_cons_putc(dev_t, int);
diff --git a/sys/arch/arm64/stand/efiboot/eficall.h b/sys/arch/arm64/stand/efiboot/eficall.h
new file mode 100644
index 00000000000..25e0d3042c5
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/eficall.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: eficall.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(__amd64__)
+
+#define EFI_CALL(_func_, ...) (_func_)(__VA_ARGS__)
+
+#else
+
+extern uint64_t efi_call(int, void *, ...);
+
+#define _call_0(_func) \
+ efi_call(0, (_func))
+#define _call_1(_func, _1) \
+ efi_call(1, (_func), (_1))
+#define _call_2(_func, _1, _2) \
+ efi_call(2, (_func), (_1), (_2))
+#define _call_3(_func, _1, _2, _3) \
+ efi_call(3, (_func), (_1), (_2), (_3))
+#define _call_4(_func, _1, _2, _3, _4) \
+ efi_call(4, (_func), (_1), (_2), (_3), (_4))
+#define _call_5(_func, _1, _2, _3, _4, _5) \
+ efi_call(5, (_func), (_1), (_2), (_3), (_4), (_5))
+#define _call_6(_func, _1, _2, _3, _4, _5, _6) \
+ efi_call(6, (_func), (_1), (_2), (_3), (_4), (_5), (_6))
+#define _call_7(_func, _1, _2, _3, _4, _5, _6, _7) \
+ efi_call(7, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7))
+#define _call_8(_func, _1, _2, _3, _4, _5, _6, _7, _8) \
+ efi_call(8, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8))
+#define _call_9(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
+ efi_call(9, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8), (_9))
+
+#define _efi_call_fn(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _fn, ...) _fn
+
+#define EFI_CALL(...) \
+ _efi_call_fn(__VA_ARGS__, _call_9, _call_8, _call_7, _call_6, _call_5, \
+ _call_4, _call_3, _call_2, _call_1, _call_1)(__VA_ARGS__)
+#endif
diff --git a/sys/arch/arm64/stand/efiboot/efidev.c b/sys/arch/arm64/stand/efiboot/efidev.c
new file mode 100644
index 00000000000..fc61cfa7859
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/efidev.c
@@ -0,0 +1,229 @@
+/* $OpenBSD: efidev.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ * Copyright (c) 2016 Mark Kettenis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <sys/disklabel.h>
+#include <lib/libz/zlib.h>
+
+#include "libsa.h"
+
+#include <efi.h>
+#include "eficall.h"
+
+extern EFI_BOOT_SERVICES *BS;
+
+extern int debug;
+
+#include "disk.h"
+#include "efidev.h"
+
+#define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE)
+#define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed))
+
+extern EFI_BLOCK_IO *disk;
+struct diskinfo diskinfo;
+
+static EFI_STATUS
+ efid_io(int, efi_diskinfo_t, u_int, int, void *);
+static int efid_diskio(int, struct diskinfo *, u_int, int, void *);
+
+static EFI_STATUS
+efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf)
+{
+ EFI_STATUS status = EFI_SUCCESS;
+ EFI_PHYSICAL_ADDRESS addr;
+ caddr_t data;
+
+ if (ed->blkio->Media->BlockSize != DEV_BSIZE)
+ return (EFI_UNSUPPORTED);
+
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(nsect * DEV_BSIZE), &addr);
+ if (EFI_ERROR(status))
+ goto on_eio;
+ data = (caddr_t)(uintptr_t)addr;
+
+ switch (rw) {
+ case F_READ:
+ status = EFI_CALL(ed->blkio->ReadBlocks,
+ ed->blkio, ed->mediaid, off,
+ nsect * DEV_BSIZE, data);
+ if (EFI_ERROR(status))
+ goto on_eio;
+ memcpy(buf, data, nsect * DEV_BSIZE);
+ break;
+ case F_WRITE:
+ if (ed->blkio->Media->ReadOnly)
+ goto on_eio;
+ /* XXX not yet */
+ goto on_eio;
+ break;
+ }
+ return (EFI_SUCCESS);
+
+on_eio:
+ BS->FreePages(addr, EFI_SIZE_TO_PAGES(nsect * DEV_BSIZE));
+
+ return (status);
+}
+
+static int
+efid_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf)
+{
+ EFI_STATUS status;
+
+ status = efid_io(rw, &dip->ed, off, nsect, buf);
+
+ return ((EFI_ERROR(status))? -1 : 0);
+}
+
+/*
+ * Read disk label from the device.
+ */
+int
+efi_getdisklabel(struct diskinfo *dip)
+{
+ char *msg;
+ int sector;
+ size_t rsize;
+ struct disklabel *lp;
+ char buf[DEV_BSIZE];
+
+ /*
+ * Find OpenBSD Partition in DOS partition table.
+ */
+ sector = 0;
+ if (efistrategy(dip, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize))
+ return EOFFSET;
+
+ if (*(u_int16_t *)&buf[DOSMBR_SIGNATURE_OFF] == DOSMBR_SIGNATURE) {
+ int i;
+ struct dos_partition *dp = (struct dos_partition *)buf;
+
+ /*
+ * Lookup OpenBSD slice. If there is none, go ahead
+ * and try to read the disklabel off sector #0.
+ */
+
+ memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp));
+ for (i = 0; i < NDOSPART; i++) {
+ if (dp[i].dp_typ == DOSPTYP_OPENBSD) {
+ sector = letoh32(dp[i].dp_start);
+ break;
+ }
+ }
+ }
+
+ if (efistrategy(dip, F_READ, sector + DOS_LABELSECTOR, DEV_BSIZE,
+ buf, &rsize))
+ return EOFFSET;
+
+ if ((msg = getdisklabel(buf + LABELOFFSET, &dip->disklabel)))
+ printf("sd%d: getdisklabel: %s\n", 0, msg);
+
+ lp = &dip->disklabel;
+
+ /* check partition */
+ if ((dip->sc_part >= lp->d_npartitions) ||
+ (lp->d_partitions[dip->sc_part].p_fstype == FS_UNUSED)) {
+ DPRINTF(("illegal partition\n"));
+ return (EPART);
+ }
+
+ return (0);
+}
+
+int
+efiopen(struct open_file *f, ...)
+{
+ struct diskinfo *dip = &diskinfo;
+ va_list ap;
+ u_int unit, part;
+ int error;
+
+ if (disk == NULL)
+ return (ENXIO);
+
+ va_start(ap, f);
+ unit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ if (unit != 0)
+ return (ENXIO);
+
+ diskinfo.ed.blkio = disk;
+ diskinfo.ed.mediaid = disk->Media->MediaId;
+ diskinfo.sc_part = part;
+
+ error = efi_getdisklabel(&diskinfo);
+ if (error)
+ return (error);
+
+ f->f_devdata = dip;
+
+ return 0;
+}
+
+int
+efistrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ struct diskinfo *dip = (struct diskinfo *)devdata;
+ int error = 0;
+ size_t nsect;
+
+ nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
+ blk += dip->disklabel.d_partitions[B_PARTITION(dip->sc_part)].p_offset;
+
+ if (blk < 0)
+ error = EINVAL;
+ else
+ error = efid_diskio(rw, dip, blk, nsect, buf);
+
+ if (rsize != NULL)
+ *rsize = nsect * DEV_BSIZE;
+
+ return (error);
+}
+
+int
+eficlose(struct open_file *f)
+{
+ f->f_devdata = NULL;
+
+ return 0;
+}
+
+int
+efiioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return 0;
+}
diff --git a/sys/arch/arm64/stand/efiboot/efidev.h b/sys/arch/arm64/stand/efiboot/efidev.h
new file mode 100644
index 00000000000..a771bfcc1f7
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/efidev.h
@@ -0,0 +1,35 @@
+/* $OpenBSD: efidev.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff
+ * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* efidev.c */
+int efiopen(struct open_file *, ...);
+int efistrategy(void *, int, daddr32_t, size_t, void *, size_t *);
+int eficlose(struct open_file *);
+int efiioctl(struct open_file *, u_long, void *);
diff --git a/sys/arch/arm64/stand/efiboot/exec.c b/sys/arch/arm64/stand/efiboot/exec.c
new file mode 100644
index 00000000000..c12f137c896
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/exec.c
@@ -0,0 +1,87 @@
+/* $OpenBSD: exec.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2006, 2016 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/reboot.h>
+#include <dev/cons.h>
+
+#include <lib/libkern/libkern.h>
+#include <lib/libsa/loadfile.h>
+#include <sys/exec_elf.h>
+
+#include <efi.h>
+#include <stand/boot/cmd.h>
+
+#include "efiboot.h"
+#include "libsa.h"
+
+typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn));
+
+void
+run_loadfile(u_long *marks, int howto)
+{
+ Elf_Ehdr *elf = (Elf_Ehdr *)marks[MARK_SYM];
+ Elf_Shdr *shp = (Elf_Shdr *)(marks[MARK_SYM] + elf->e_shoff);
+ u_long esym = marks[MARK_END] & 0x7fffffffff;
+ u_long offset = 0;
+ char args[256];
+ char *cp;
+ void *fdt;
+ int i;
+
+ /*
+ * Tell locore.S where the symbol table ends by setting
+ * 'esym', which should be the first word in the .data
+ * section.
+ */
+ for (i = 0; i < elf->e_shnum; i++) {
+ /* XXX Assume .data is the first writable segment. */
+ if (shp[i].sh_flags & SHF_WRITE) {
+ /* XXX We have to store the virtual address. */
+ esym |= shp[i].sh_addr & 0xffffff8000000000;
+ *(u_long *)(LOADADDR(shp[i].sh_addr)) = esym;
+ break;
+ }
+ }
+
+ snprintf(args, sizeof(args) - 8, "%s:%s", cmd.bootdev, cmd.image);
+ cp = args + strlen(args);
+
+ *cp++ = ' ';
+ *cp = '-';
+ if (howto & RB_ASKNAME)
+ *++cp = 'a';
+ if (howto & RB_CONFIG)
+ *++cp = 'c';
+ if (howto & RB_SINGLE)
+ *++cp = 's';
+ if (howto & RB_KDB)
+ *++cp = 'd';
+ if (*cp == '-')
+ *--cp = 0;
+ else
+ *++cp = 0;
+
+ fdt = efi_makebootargs(args);
+
+ efi_cleanup();
+
+ (*(startfuncp)(marks[MARK_ENTRY]))((void *)esym, 0, fdt);
+
+ /* NOTREACHED */
+}
diff --git a/sys/arch/arm64/stand/efiboot/fdt.c b/sys/arch/arm64/stand/efiboot/fdt.c
new file mode 100644
index 00000000000..cbd12322575
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/fdt.c
@@ -0,0 +1,574 @@
+/* $OpenBSD: fdt.c,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
+ * Copyright (c) 2009, 2016 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <lib/libkern/libkern.h>
+
+#include "fdt.h"
+
+unsigned int fdt_check_head(void *);
+char *fdt_get_str(uint32_t);
+void *skip_property(uint32_t *);
+void *skip_props(uint32_t *);
+void *skip_node_name(uint32_t *);
+void *skip_node(void *);
+void *fdt_parent_node_recurse(void *, void *);
+
+static int tree_inited = 0;
+static struct fdt tree;
+
+unsigned int
+fdt_check_head(void *fdt)
+{
+ struct fdt_head *fh;
+ uint32_t *ptr;
+
+ fh = fdt;
+ ptr = (uint32_t *)fdt;
+
+ if (betoh32(fh->fh_magic) != FDT_MAGIC)
+ return 0;
+
+ if (betoh32(fh->fh_version) > FDT_CODE_VERSION)
+ return 0;
+
+ if (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4))) !=
+ FDT_NODE_BEGIN)
+ return 0;
+
+ /* check for end signature on version 17 blob */
+ if ((betoh32(fh->fh_version) >= 17) &&
+ (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) +
+ (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END))
+ return 0;
+
+ return betoh32(fh->fh_version);
+}
+
+/*
+ * Initializes internal structures of module.
+ * Has to be called once.
+ */
+int
+fdt_init(void *fdt)
+{
+ int version;
+
+ memset(&tree, 0, sizeof(struct fdt));
+ tree_inited = 0;
+
+ if (!fdt)
+ return 0;
+
+ if (!(version = fdt_check_head(fdt)))
+ return 0;
+
+ tree.header = (struct fdt_head *)fdt;
+ tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off);
+ tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off);
+ tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off);
+ tree.end = (char *)fdt + betoh32(tree.header->fh_size);
+ tree.version = version;
+ tree.strings_size = betoh32(tree.header->fh_strings_size);
+ if (tree.version >= 17)
+ tree.struct_size = betoh32(tree.header->fh_struct_size);
+ tree_inited = 1;
+
+ return version;
+}
+
+void
+fdt_finalize(void)
+{
+ char *start = (char *)tree.header;
+
+ tree.header->fh_size = htobe32(tree.end - start);
+ tree.header->fh_struct_off = htobe32(tree.tree - start);
+ tree.header->fh_strings_off = htobe32(tree.strings - start);
+ tree.header->fh_reserve_off = htobe32(tree.memory - start);
+ tree.header->fh_strings_size = htobe32(tree.strings_size);
+ if (tree.version >= 17)
+ tree.header->fh_struct_size = htobe32(tree.struct_size);
+}
+
+/*
+ * Return the size of the FDT.
+ */
+size_t
+fdt_get_size(void *fdt)
+{
+ if (!fdt)
+ return 0;
+
+ if (!fdt_check_head(fdt))
+ return 0;
+
+ return betoh32(((struct fdt_head *)fdt)->fh_size);
+}
+
+/*
+ * Retrieve string pointer from strings table.
+ */
+char *
+fdt_get_str(uint32_t num)
+{
+ if (num > tree.strings_size)
+ return NULL;
+ return (tree.strings) ? (tree.strings + num) : NULL;
+}
+
+int
+fdt_add_str(char *name)
+{
+ size_t len = roundup(strlen(name) + 1, sizeof(uint32_t));
+ char *end = tree.strings + tree.strings_size;
+
+ memmove(end + len, end, tree.end - end);
+ tree.strings_size += len;
+ if (tree.tree > tree.strings)
+ tree.tree += len;
+ if (tree.memory > tree.strings)
+ tree.memory += len;
+ tree.end += len;
+ memcpy(end, name, len);
+
+ return (end - tree.strings);
+}
+
+/*
+ * Utility functions for skipping parts of tree.
+ */
+void *
+skip_property(uint32_t *ptr)
+{
+ uint32_t size;
+
+ size = betoh32(*(ptr + 1));
+ /* move forward by magic + size + nameid + rounded up property size */
+ ptr += 3 + roundup(size, sizeof(uint32_t)) / sizeof(uint32_t);
+
+ return ptr;
+}
+
+void *
+skip_props(uint32_t *ptr)
+{
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ ptr = skip_property(ptr);
+ }
+ return ptr;
+}
+
+void *
+skip_node_name(uint32_t *ptr)
+{
+ /* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */
+ return ptr + roundup(strlen((char *)ptr) + 1,
+ sizeof(uint32_t)) / sizeof(uint32_t);
+}
+
+/*
+ * Retrieves node property, the returned pointer is inside the fdt tree,
+ * so we should not modify content pointed by it directly.
+ */
+int
+fdt_node_property(void *node, char *name, char **out)
+{
+ uint32_t *ptr;
+ uint32_t nameid;
+ char *tmp;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
+ tmp = fdt_get_str(nameid);
+ if (!strcmp(name, tmp)) {
+ *out = (char *)(ptr + 3); /* beginning of the value */
+ return betoh32(*(ptr + 1)); /* size of value */
+ }
+ ptr = skip_property(ptr);
+ }
+ return 0;
+}
+
+int
+fdt_node_set_property(void *node, char *name, char *data, int len)
+{
+ uint32_t *ptr, *next;
+ uint32_t nameid;
+ uint32_t curlen;
+ size_t delta;
+ char *tmp;
+
+ if (!tree_inited)
+ return 0;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ while (betoh32(*ptr) == FDT_PROPERTY) {
+ nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
+ tmp = fdt_get_str(nameid);
+ next = skip_property(ptr);
+ if (!strcmp(name, tmp)) {
+ curlen = betoh32(*(ptr + 1));
+ delta = roundup(len, sizeof(uint32_t)) -
+ roundup(curlen, sizeof(uint32_t));
+ memmove((char *)next + delta, next,
+ tree.end - (char *)next);
+ tree.struct_size += delta;
+ if (tree.strings > tree.tree)
+ tree.strings += delta;
+ if (tree.memory > tree.tree)
+ tree.memory += delta;
+ tree.end += delta;
+ *(ptr + 1) = htobe32(len);
+ memcpy(ptr + 3, data, len);
+ return 1;
+ }
+ ptr = next;
+ }
+ return 0;
+}
+
+int
+fdt_node_add_property(void *node, char *name, char *data, int len)
+{
+ char *dummy;
+
+ if (!tree_inited)
+ return 0;
+
+ if (!fdt_node_property(node, name, &dummy)) {
+ uint32_t *ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return 0;
+
+ ptr = skip_node_name(ptr + 1);
+
+ memmove(ptr + 3, ptr, tree.end - (char *)ptr);
+ tree.struct_size += 3 * sizeof(uint32_t);
+ if (tree.strings > tree.tree)
+ tree.strings += 3 * sizeof(uint32_t);
+ if (tree.memory > tree.tree)
+ tree.memory += 3 * sizeof(uint32_t);
+ tree.end += 3 * sizeof(uint32_t);
+ *ptr++ = htobe32(FDT_PROPERTY);
+ *ptr++ = htobe32(0);
+ *ptr++ = htobe32(fdt_add_str(name));
+ }
+
+ return fdt_node_set_property(node, name, data, len);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node,
+ * returns pointer to next node, no matter if it exists or not.
+ */
+void *
+skip_node(void *node)
+{
+ uint32_t *ptr = node;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ return (ptr + 1);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node,
+ * returns pointer to next node if exists, otherwise returns NULL.
+ * If passed 0 will return first node of the tree (root).
+ */
+void *
+fdt_next_node(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (node == NULL) {
+ ptr = (uint32_t *)tree.tree;
+ return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL;
+ }
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+
+ /* skip children */
+ while (betoh32(*ptr) == FDT_NODE_BEGIN)
+ ptr = skip_node(ptr);
+
+ if (betoh32(*ptr) != FDT_NODE_END)
+ return NULL;
+
+ if (betoh32(*(ptr + 1)) != FDT_NODE_BEGIN)
+ return NULL;
+
+ return (ptr + 1);
+}
+
+/*
+ * Retrieves next node, skipping all the children nodes of the pointed node
+ */
+void *
+fdt_child_node(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ ptr++;
+
+ ptr = skip_node_name(ptr);
+ ptr = skip_props(ptr);
+ /* check if there is a child node */
+ return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL;
+}
+
+/*
+ * Retrieves node name.
+ */
+char *
+fdt_node_name(void *node)
+{
+ uint32_t *ptr;
+
+ if (!tree_inited)
+ return NULL;
+
+ ptr = node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return NULL;
+
+ return (char *)(ptr + 1);
+}
+
+void *
+fdt_find_node(char *name)
+{
+ void *node = fdt_next_node(0);
+ const char *p = name;
+
+ if (!tree_inited)
+ return NULL;
+
+ if (*p != '/')
+ return NULL;
+
+ while (*p) {
+ void *child;
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (*p == 0)
+ return node;
+ q = strchr(p, '/');
+ if (q == NULL)
+ q = p + strlen(p);
+
+ for (child = fdt_child_node(node); child;
+ child = fdt_next_node(child)) {
+ if (strncmp(p, fdt_node_name(child), q - p) == 0) {
+ node = child;
+ break;
+ }
+ }
+
+ p = q;
+ }
+
+ return node;
+}
+
+void *
+fdt_parent_node_recurse(void *pnode, void *child)
+{
+ void *node = fdt_child_node(pnode);
+ void *tmp;
+
+ while (node && (node != child)) {
+ if ((tmp = fdt_parent_node_recurse(node, child)))
+ return tmp;
+ node = fdt_next_node(node);
+ }
+ return (node) ? pnode : NULL;
+}
+
+void *
+fdt_parent_node(void *node)
+{
+ void *pnode = fdt_next_node(0);
+
+ if (!tree_inited)
+ return NULL;
+
+ if (node == pnode)
+ return NULL;
+
+ return fdt_parent_node_recurse(pnode, node);
+}
+
+int
+fdt_node_is_compatible(void *node, const char *name)
+{
+ char *data;
+ int len;
+
+ len = fdt_node_property(node, "compatible", &data);
+ while (len > 0) {
+ if (strcmp(data, name) == 0)
+ return 1;
+ len -= strlen(data) + 1;
+ data += strlen(data) + 1;
+ }
+
+ return 0;
+}
+
+#ifdef DEBUG
+/*
+ * Debug methods for printing whole tree, particular odes and properies
+ */
+void *
+fdt_print_property(void *node, int level)
+{
+ uint32_t *ptr;
+ char *tmp, *value;
+ int cnt;
+ uint32_t nameid, size;
+
+ ptr = (uint32_t *)node;
+
+ if (!tree_inited)
+ return NULL;
+
+ if (betoh32(*ptr) != FDT_PROPERTY)
+ return ptr; /* should never happen */
+
+ /* extract property name_id and size */
+ size = betoh32(*++ptr);
+ nameid = betoh32(*++ptr);
+
+ for (cnt = 0; cnt < level; cnt++)
+ printf("\t");
+
+ tmp = fdt_get_str(nameid);
+ printf("\t%s : ", tmp ? tmp : "NO_NAME");
+
+ ptr++;
+ value = (char *)ptr;
+
+ if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") ||
+ !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") ||
+ !strcmp(tmp, "linux,stdout-path")) {
+ printf("%s", value);
+ } else if (!strcmp(tmp, "clock-frequency") ||
+ !strcmp(tmp, "timebase-frequency")) {
+ printf("%d", betoh32(*((unsigned int *)value)));
+ } else {
+ for (cnt = 0; cnt < size; cnt++) {
+ if ((cnt % sizeof(uint32_t)) == 0)
+ printf(" ");
+ printf("%x%x", value[cnt] >> 4, value[cnt] & 0xf);
+ }
+ }
+ ptr += roundup(size, sizeof(uint32_t)) / sizeof(uint32_t);
+ printf("\n");
+
+ return ptr;
+}
+
+void
+fdt_print_node(void *node, int level)
+{
+ uint32_t *ptr;
+ int cnt;
+
+ ptr = (uint32_t *)node;
+
+ if (betoh32(*ptr) != FDT_NODE_BEGIN)
+ return;
+
+ ptr++;
+
+ for (cnt = 0; cnt < level; cnt++)
+ printf("\t");
+ printf("%s :\n", fdt_node_name(node));
+ ptr = skip_node_name(ptr);
+
+ while (betoh32(*ptr) == FDT_PROPERTY)
+ ptr = fdt_print_property(ptr, level);
+}
+
+void
+fdt_print_node_recurse(void *node, int level)
+{
+ void *child;
+
+ fdt_print_node(node, level);
+ for (child = fdt_child_node(node); child; child = fdt_next_node(child))
+ fdt_print_node_recurse(child, level + 1);
+}
+
+void
+fdt_print_tree(void)
+{
+ fdt_print_node_recurse(fdt_next_node(0), 0);
+}
+#endif
diff --git a/sys/arch/arm64/stand/efiboot/fdt.h b/sys/arch/arm64/stand/efiboot/fdt.h
new file mode 100644
index 00000000000..9438f3c0a76
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/fdt.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: fdt.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct fdt_head {
+ uint32_t fh_magic;
+ uint32_t fh_size;
+ uint32_t fh_struct_off;
+ uint32_t fh_strings_off;
+ uint32_t fh_reserve_off;
+ uint32_t fh_version;
+ uint32_t fh_comp_ver; /* last compatible version */
+ uint32_t fh_boot_cpu_id; /* fh_version >=2 */
+ uint32_t fh_strings_size; /* fh_version >=3 */
+ uint32_t fh_struct_size; /* fh_version >=17 */
+};
+
+struct fdt {
+ struct fdt_head *header;
+ char *tree;
+ char *strings;
+ char *memory;
+ char *end;
+ int version;
+ int strings_size;
+ int struct_size;
+};
+
+#define FDT_MAGIC 0xd00dfeed
+#define FDT_NODE_BEGIN 0x01
+#define FDT_NODE_END 0x02
+#define FDT_PROPERTY 0x03
+#define FDT_NOP 0x04
+#define FDT_END 0x09
+
+#define FDT_CODE_VERSION 0x11
+
+int fdt_init(void *);
+void fdt_finalize(void);
+size_t fdt_get_size(void *);
+void *fdt_next_node(void *);
+void *fdt_child_node(void *);
+char *fdt_node_name(void *);
+void *fdt_find_node(char *);
+int fdt_node_property(void *, char *, char **);
+int fdt_node_set_property(void *, char *, char *, int);
+int fdt_node_add_property(void *, char *, char *, int);
+void *fdt_parent_node(void *);
+int fdt_node_is_compatible(void *, const char *);
+#ifdef DEBUG
+void *fdt_print_property(void *, int);
+void fdt_print_node(void *, int);
+void fdt_print_tree(void);
+#endif
diff --git a/sys/arch/arm64/stand/efiboot/heap.h b/sys/arch/arm64/stand/efiboot/heap.h
new file mode 100644
index 00000000000..ba8cb8c55da
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/heap.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: heap.h,v 1.1 2016/12/17 23:38:33 patrick 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/arm64/stand/efiboot/ldscript.arm64 b/sys/arch/arm64/stand/efiboot/ldscript.arm64
new file mode 100644
index 00000000000..cdf6876d6df
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/ldscript.arm64
@@ -0,0 +1,85 @@
+/* $OpenBSD: ldscript.arm64,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*
+OUTPUT_FORMAT("elf64-aarch64-freebsd", "elf64-aarch64-freebsd", "elf64-aarch64-freebsd")
+*/
+OUTPUT_ARCH(aarch64)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ ImageBase = .;
+ .text : {
+ *(.peheader)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.plt)
+ } =0xD4200000
+ . = ALIGN(16);
+ .data : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ *(.rodata1)
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
+ *(.opd)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.data1)
+ *(.plabel)
+
+ . = ALIGN(16);
+ __bss_start = .;
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss *.bss.*)
+ *(COMMON)
+ . = ALIGN(16);
+ __bss_end = .;
+ }
+ . = ALIGN(16);
+ set_Xcommand_set : {
+ __start_set_Xcommand_set = .;
+ *(set_Xcommand_set)
+ __stop_set_Xcommand_set = .;
+ }
+ set_Xficl_compile_set : {
+ __start_set_Xficl_compile_set = .;
+ *(set_Xficl_compile_set)
+ __stop_set_Xficl_compile_set = .;
+ }
+ . = ALIGN(16);
+ __gp = .;
+ .sdata : {
+ *(.got.plt .got)
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ *(dynsbss)
+ *(.scommon)
+ }
+ . = ALIGN(16);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(16);
+ .rela.dyn : {
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ *(.rela.plt)
+ *(.relset_*)
+ *(.rela.dyn .rela.dyn.*)
+ }
+ . = ALIGN(16);
+ .reloc : { *(.reloc) }
+ . = ALIGN(16);
+ .dynsym : { *(.dynsym) }
+ _edata = .;
+
+ /* Unused sections */
+ .dynstr : { *(.dynstr) }
+ .hash : { *(.hash) }
+}
diff --git a/sys/arch/arm64/stand/efiboot/libsa.h b/sys/arch/arm64/stand/efiboot/libsa.h
new file mode 100644
index 00000000000..a75b5589bb5
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/libsa.h
@@ -0,0 +1,30 @@
+/* $OpenBSD: libsa.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+
+/*
+ * Copyright (c) 2008 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <lib/libsa/stand.h>
+
+#define DEFAULT_KERNEL_ADDRESS 0
+
+#ifdef DEBUG
+#define DPRINTF(x) printf x;
+#else
+#define DPRINTF(x)
+#endif
+
+void machdep(void);
+void devboot(dev_t, char *);
diff --git a/sys/arch/arm64/stand/efiboot/self_reloc.c b/sys/arch/arm64/stand/efiboot/self_reloc.c
new file mode 100644
index 00000000000..5f23698d6a3
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/self_reloc.c
@@ -0,0 +1,122 @@
+/* $OpenBSD: self_reloc.c,v 1.1 2016/12/17 23:38:33 patrick 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 <sys/exec_elf.h>
+#include <machine/reloc.h>
+
+#if defined(__aarch64__) || defined(__amd64__)
+#define ElfW_Rel Elf64_Rela
+#define ElfW_Dyn Elf64_Dyn
+#define ELFW_R_TYPE ELF64_R_TYPE
+#define ELF_RELA
+#elif defined(__arm__) || defined(__i386__)
+#define ElfW_Rel Elf32_Rel
+#define ElfW_Dyn Elf32_Dyn
+#define ELFW_R_TYPE ELF32_R_TYPE
+#else
+#error architecture not supported
+#endif
+#if defined(__aarch64__)
+#define RELOC_TYPE_NONE R_AARCH64_NONE
+#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE
+#elif defined(__amd64__)
+#define RELOC_TYPE_NONE R_X86_64_NONE
+#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE
+#elif defined(__arm__)
+#define RELOC_TYPE_NONE R_ARM_NONE
+#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE
+#elif defined(__i386__)
+#define RELOC_TYPE_NONE R_386_NONE
+#define RELOC_TYPE_RELATIVE R_386_RELATIVE
+#endif
+
+void self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic);
+
+/*
+ * A simple elf relocator.
+ */
+void
+self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic)
+{
+ Elf_Word relsz, relent;
+ Elf_Addr *newaddr;
+ ElfW_Rel *rel = 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 *)(void *)((caddr_t) rel + relent);
+ }
+}
diff --git a/sys/arch/arm64/stand/efiboot/start.S b/sys/arch/arm64/stand/efiboot/start.S
new file mode 100644
index 00000000000..0720a2195e2
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/start.S
@@ -0,0 +1,166 @@
+/* $OpenBSD: start.S,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * We need to be a PE32+ file for EFI. On some architectures we can use
+ * objcopy to create the correct file, however on arm64 we need to do
+ * it ourselves.
+ */
+
+#define IMAGE_FILE_MACHINE_ARM64 0xaa64
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+
+ .section .peheader
+efi_start:
+ /* The MS-DOS Stub, only used to get the offset of the COFF header */
+ .ascii "MZ"
+ .short 0
+ .space 0x38
+ .long pe_sig - efi_start
+
+ /* The PE32 Signature. Needs to be 8-byte aligned */
+ .align 3
+pe_sig:
+ .ascii "PE"
+ .short 0
+coff_head:
+ .short IMAGE_FILE_MACHINE_ARM64 /* AArch64 file */
+ .short 2 /* 2 Sections */
+ .long 0 /* Timestamp */
+ .long 0 /* No symbol table */
+ .long 0 /* No symbols */
+ .short section_table - optional_header /* Optional header size */
+ .short 0 /* Characteristics TODO: Fill in */
+
+optional_header:
+ .short 0x020b /* PE32+ (64-bit addressing) */
+ .byte 0 /* Major linker version */
+ .byte 0 /* Minor linker version */
+ .long _edata - _end_header /* Code size */
+ .long 0 /* No initialized data */
+ .long 0 /* No uninitialized data */
+ .long _start - efi_start /* Entry point */
+ .long _end_header - efi_start /* Start of code */
+
+optional_windows_header:
+ .quad 0 /* Image base */
+ .long 32 /* Section Alignment */
+ .long 8 /* File alignment */
+ .short 0 /* Major OS version */
+ .short 0 /* Minor OS version */
+ .short 0 /* Major image version */
+ .short 0 /* Minor image version */
+ .short 0 /* Major subsystem version */
+ .short 0 /* Minor subsystem version */
+ .long 0 /* Win32 version */
+ .long _edata - efi_start /* Image size */
+ .long _end_header - efi_start /* Header size */
+ .long 0 /* Checksum */
+ .short 0xa /* Subsystem (EFI app) */
+ .short 0 /* DLL Characteristics */
+ .quad 0 /* Stack reserve */
+ .quad 0 /* Stack commit */
+ .quad 0 /* Heap reserve */
+ .quad 0 /* Heap commit */
+ .long 0 /* Loader flags */
+ .long 6 /* Number of RVAs */
+
+ /* RVAs: */
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+
+section_table:
+ /* We need a .reloc section for EFI */
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long 0 /* Virtual size */
+ .long 0 /* Virtual address */
+ .long 0 /* Size of raw data */
+ .long 0 /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */
+
+ /* The contents of the loader */
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 /* Pad to 8 bytes */
+ .long _edata - _end_header /* Virtual size */
+ .long _end_header - efi_start /* Virtual address */
+ .long _edata - _end_header /* Size of raw data */
+ .long _end_header - efi_start /* Pointer to raw data */
+ .long 0 /* Pointer to relocations */
+ .long 0 /* Pointer to line numbers */
+ .short 0 /* Number of relocations */
+ .short 0 /* Number of line numbers */
+ .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \
+ IMAGE_SCN_MEM_READ) /* Characteristics */
+_end_header:
+
+ .text
+ .globl _start
+_start:
+ /* Save the boot params to the stack */
+ stp x0, x1, [sp, #-16]!
+
+ adr x0, __bss_start
+ adr x1, __bss_end
+
+ b 2f
+
+1:
+ stp xzr, xzr, [x0], #16
+2:
+ cmp x0, x1
+ b.lo 1b
+
+ adr x0, ImageBase
+ adr x1, _DYNAMIC
+
+ bl self_reloc
+
+ ldp x0, x1, [sp], #16
+
+ bl efi_main
+
+1: b 1b