diff options
author | 2016-12-17 23:38:33 +0000 | |
---|---|---|
committer | 2016-12-17 23:38:33 +0000 | |
commit | f24071e5a82bde237999ed17cfea827c436463e8 (patch) | |
tree | e8624b507581722d2d79bb0e61ae37b1c6b4b4bf | |
parent | sync (diff) | |
download | wireguard-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.
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, ®)) + 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, ®)) + 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, ®)) + 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 |