From b78ee15e9f04ae15c3e1200df974473167524d17 Mon Sep 17 00:00:00 2001 From: Ruslan Bukin Date: Wed, 1 Jul 2015 15:51:11 +0000 Subject: [PATCH] First cut of DTrace for AArch64. Reviewed by: andrew, emaste Sponsored by: ARM Limited Differential Revision: https://reviews.freebsd.org/D2738 --- Makefile.inc1 | 6 +- .../lib/libdtrace/aarch64/dt_isadep.c | 139 ++++++++ .../lib/libdtrace/common/dt_link.c | 20 +- cddl/lib/Makefile | 6 +- cddl/lib/libdtrace/Makefile | 20 +- cddl/usr.sbin/Makefile | 2 +- lib/Makefile | 7 +- sys/arm64/arm64/exception.S | 1 + sys/arm64/arm64/trap.c | 18 + .../uts/aarch64/dtrace/fasttrap_isa.c | 29 ++ .../uts/aarch64/sys/fasttrap_isa.h | 46 +++ .../opensolaris/uts/common/dtrace/dtrace.c | 3 +- .../opensolaris/uts/common/sys/dtrace.h | 28 ++ sys/cddl/dev/dtrace/aarch64/dtrace_asm.S | 173 ++++++++++ sys/cddl/dev/dtrace/aarch64/dtrace_isa.c | 287 ++++++++++++++++ sys/cddl/dev/dtrace/aarch64/dtrace_subr.c | 311 ++++++++++++++++++ sys/cddl/dev/dtrace/aarch64/regset.h | 51 +++ sys/cddl/dev/fbt/aarch64/fbt_isa.c | 180 ++++++++++ sys/cddl/dev/fbt/aarch64/fbt_isa.h | 30 ++ sys/cddl/dev/lockstat/lockstat.c | 5 +- sys/cddl/dev/profile/profile.c | 5 + sys/conf/files.arm64 | 4 + sys/modules/dtrace/Makefile | 2 +- sys/modules/dtrace/dtraceall/dtraceall.c | 3 +- 24 files changed, 1349 insertions(+), 27 deletions(-) create mode 100644 cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c create mode 100644 sys/cddl/contrib/opensolaris/uts/aarch64/dtrace/fasttrap_isa.c create mode 100644 sys/cddl/contrib/opensolaris/uts/aarch64/sys/fasttrap_isa.h create mode 100644 sys/cddl/dev/dtrace/aarch64/dtrace_asm.S create mode 100644 sys/cddl/dev/dtrace/aarch64/dtrace_isa.c create mode 100644 sys/cddl/dev/dtrace/aarch64/dtrace_subr.c create mode 100644 sys/cddl/dev/dtrace/aarch64/regset.h create mode 100644 sys/cddl/dev/fbt/aarch64/fbt_isa.c create mode 100644 sys/cddl/dev/fbt/aarch64/fbt_isa.h diff --git a/Makefile.inc1 b/Makefile.inc1 index a080836118c8..abb3b1d71cd9 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1766,9 +1766,9 @@ cddl/lib/libctf__L: lib/libz__L .endif # cddl/lib/libdtrace requires lib/libproc and lib/librtld_db; it's only built # on select architectures though (see cddl/lib/Makefile) -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \ - ${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" || \ - ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_ARCH} == "amd64" || \ + ${MACHINE_CPUARCH} == "arm" || ${MACHINE_ARCH} == "i386" || \ + ${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" _prebuild_libs+= lib/libproc lib/librtld_db .endif diff --git a/cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c new file mode 100644 index 000000000000..9f5af8570490 --- /dev/null +++ b/cddl/contrib/opensolaris/lib/libdtrace/aarch64/dt_isadep.c @@ -0,0 +1,139 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * Copyright 2014 Howard Su + * Copyright 2015 George V. Neville-Neil + * Copyright 2015 Ruslan Bukin + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(sun) +#include +#endif + +/*ARGSUSED*/ +int +dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, + fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) +{ + + ftp->ftps_type = DTFTP_ENTRY; + ftp->ftps_pc = (uintptr_t)symp->st_value; + ftp->ftps_size = (size_t)symp->st_size; + ftp->ftps_noffs = 1; + ftp->ftps_offs[0] = 0; + + if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { + dt_dprintf("fasttrap probe creation ioctl failed: %s\n", + strerror(errno)); + return (dt_set_errno(dtp, errno)); + } + + return (1); +} + +int +dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, + fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) +{ + + dt_dprintf("%s: unimplemented\n", __func__); + + return (DT_PROC_ERR); +} + +/*ARGSUSED*/ +int +dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, + fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) +{ + + if (!ALIGNED_POINTER(off, 4)) + return (DT_PROC_ALIGN); + + ftp->ftps_type = DTFTP_OFFSETS; + ftp->ftps_pc = (uintptr_t)symp->st_value; + ftp->ftps_size = (size_t)symp->st_size; + ftp->ftps_noffs = 1; + ftp->ftps_offs[0] = off; + + if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { + dt_dprintf("fasttrap probe creation ioctl failed: %s\n", + strerror(errno)); + return (dt_set_errno(dtp, errno)); + } + + return (1); +} + +/*ARGSUSED*/ +int +dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, + fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) +{ + ulong_t i; + + ftp->ftps_type = DTFTP_OFFSETS; + ftp->ftps_pc = (uintptr_t)symp->st_value; + ftp->ftps_size = (size_t)symp->st_size; + ftp->ftps_noffs = 0; + + /* + * If we're matching against everything, just iterate through each + * instruction in the function, otherwise look for matching offset + * names by constructing the string and comparing it against the + * pattern. + */ + if (strcmp("*", pattern) == 0) { + for (i = 0; i < symp->st_size; i += 4) { + ftp->ftps_offs[ftp->ftps_noffs++] = i; + } + } else { + char name[sizeof (i) * 2 + 1]; + + for (i = 0; i < symp->st_size; i += 4) { + (void) sprintf(name, "%lx", i); + if (gmatch(name, pattern)) + ftp->ftps_offs[ftp->ftps_noffs++] = i; + } + } + + if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { + dt_dprintf("fasttrap probe creation ioctl failed: %s\n", + strerror(errno)); + return (dt_set_errno(dtp, errno)); + } + + return (ftp->ftps_noffs); +} diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c index f9b9625d6af6..f574cf763804 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c @@ -227,7 +227,10 @@ prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) s = &dofs[dofrh->dofr_tgtsec]; for (j = 0; j < nrel; j++) { -#if defined(__arm__) +#if defined(__aarch64__) +/* XXX */ +printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); +#elif defined(__arm__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__i386) || defined(__amd64) @@ -426,7 +429,9 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) s = &dofs[dofrh->dofr_tgtsec]; for (j = 0; j < nrel; j++) { -#if defined(__arm__) +#if defined(__aarch64__) +/* XXX */ +#elif defined(__arm__) /* XXX */ #elif defined(__mips__) /* XXX */ @@ -822,7 +827,16 @@ dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, return (ret); } -#if defined(__arm__) +#if defined(__aarch64__) +/* XXX */ +static int +dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, + uint32_t *off) +{ +printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); + return (0); +} +#elif defined(__arm__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, diff --git a/cddl/lib/Makefile b/cddl/lib/Makefile index 48a77abb5107..f418993200ed 100644 --- a/cddl/lib/Makefile +++ b/cddl/lib/Makefile @@ -26,9 +26,9 @@ _libzpool= libzpool .endif .endif -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" || \ - ${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" || \ - ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_ARCH} == "amd64" || \ + ${MACHINE_CPUARCH} == "arm" || ${MACHINE_ARCH} == "i386" || \ + ${MACHINE_CPUARCH} == "mips" || ${MACHINE_CPUARCH} == "powerpc" _drti= drti _libdtrace= libdtrace .endif diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile index 128ccf5f9071..ee1d6dbb10ac 100644 --- a/cddl/lib/libdtrace/Makefile +++ b/cddl/lib/libdtrace/Makefile @@ -69,27 +69,31 @@ CFLAGS+= -I${.OBJDIR} -I${.CURDIR} \ #CFLAGS+= -DYYDEBUG -.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "aarch64" +CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/aarch64 +.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/aarch64 +.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/aarch64 +.elif ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" CFLAGS+= -I${.CURDIR}/../../../sys/cddl/dev/dtrace/x86 CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel -DDIS_MEM .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/i386 .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/${MACHINE_ARCH} .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/x86 -.elif ${MACHINE_CPUARCH} == "sparc64" -CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc -.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/sparc -.elif ${MACHINE_CPUARCH} == "mips" -CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/mips -.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/mips -.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/mips .elif ${MACHINE_CPUARCH} == "arm" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/arm .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/arm .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/arm +.elif ${MACHINE_CPUARCH} == "mips" +CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/mips +.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/mips +.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/mips .elif ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/powerpc .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/powerpc +.elif ${MACHINE_CPUARCH} == "sparc64" +CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc +.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/sparc .else # temporary hack CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile index d309075a4306..31b55b6c4196 100644 --- a/cddl/usr.sbin/Makefile +++ b/cddl/usr.sbin/Makefile @@ -30,7 +30,7 @@ _plockstat= plockstat .endif .endif -.if ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" _dtrace= dtrace _dtruss= dtruss _lockstat= lockstat diff --git a/lib/Makefile b/lib/Makefile index b8b3a52ab5ca..d17cb5d25cd1 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -215,8 +215,9 @@ _libldns= libldns # sense to build when clang is enabled at all. Furthermore, they can only be # built for certain architectures. .if ${MK_CLANG} != "no" && ${COMPILER_TYPE} == "clang" && \ - (${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" || \ - (${MACHINE_CPUARCH} == "arm" && ${MACHINE_ARCH} != "armeb")) + (${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \ + (${MACHINE_CPUARCH} == "arm" && ${MACHINE_ARCH} != "armeb") || \ + (${MACHINE_CPUARCH} == "i386")) _libclang_rt= libclang_rt .endif @@ -273,7 +274,7 @@ _libsmb= libsmb _libsmb= libsmb .endif -.if ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" _libsmb= libsmb _libproc= libproc _librtld_db= librtld_db diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S index 9568075edc94..4f457da74b9b 100644 --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); .macro save_registers el .if \el == 1 mov x18, sp + sub sp, sp, #128 .endif stp x28, x29, [sp, #-16]! stp x26, x27, [sp, #-16]! diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index a5c9d6194371..23ea30b42a3b 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -53,6 +53,10 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef KDTRACE_HOOKS +#include +#endif + #ifdef VFP #include #endif @@ -72,6 +76,8 @@ void do_el1h_sync(struct trapframe *); void do_el0_sync(struct trapframe *); void do_el0_error(struct trapframe *); +int (*dtrace_invop_jump_addr)(struct trapframe *); + static __inline void call_trapsignal(struct thread *td, int sig, u_long code) { @@ -230,6 +236,11 @@ do_el1h_sync(struct trapframe *frame) esr = READ_SPECIALREG(esr_el1); exception = ESR_ELx_EXCEPTION(esr); +#ifdef KDTRACE_HOOKS + if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception)) + return; +#endif + /* * Sanity check we are in an exception er can handle. The IL bit * is used to indicate the instruction length, except in a few @@ -252,6 +263,13 @@ do_el1h_sync(struct trapframe *frame) data_abort(frame, esr, 0); break; case EXCP_BRK: +#ifdef KDTRACE_HOOKS + if ((esr & ESR_ELx_ISS_MASK) == 0x40d && \ + dtrace_invop_jump_addr != 0) { + dtrace_invop_jump_addr(frame); + break; + } +#endif case EXCP_WATCHPT_EL1: case EXCP_SOFTSTP_EL1: #ifdef KDB diff --git a/sys/cddl/contrib/opensolaris/uts/aarch64/dtrace/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/aarch64/dtrace/fasttrap_isa.c new file mode 100644 index 000000000000..f5377a895d6c --- /dev/null +++ b/sys/cddl/contrib/opensolaris/uts/aarch64/dtrace/fasttrap_isa.c @@ -0,0 +1,29 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * XXX: Placeholder for AArch64 fasttrap code + */ diff --git a/sys/cddl/contrib/opensolaris/uts/aarch64/sys/fasttrap_isa.h b/sys/cddl/contrib/opensolaris/uts/aarch64/sys/fasttrap_isa.h new file mode 100644 index 000000000000..d85426edb417 --- /dev/null +++ b/sys/cddl/contrib/opensolaris/uts/aarch64/sys/fasttrap_isa.h @@ -0,0 +1,46 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _FASTTRAP_ISA_H +#define _FASTTRAP_ISA_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t fasttrap_instr_t; + +/* XXX: Place for AArch64 fasttrap headers */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FASTTRAP_ISA_H */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 4e5516069f97..4da94445e3ca 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -11884,7 +11884,8 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags, int i; *factor = 1; -#if defined(__amd64__) || defined(__arm__) || defined(__mips__) || defined(__powerpc__) +#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ + defined(__mips__) || defined(__powerpc__) /* * FreeBSD isn't good at limiting the amount of memory we * ask to malloc, so let's place a limit here before trying diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h index dfcdbbfc4e9d..f3ececc8f73d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h @@ -2445,6 +2445,34 @@ extern void dtrace_helpers_destroy(proc_t *); #define DTRACE_INVOP_POPM 2 #define DTRACE_INVOP_B 3 +#elif defined(__aarch64__) + +#define INSN_SIZE 4 + +#define B_MASK 0xff000000 +#define B_DATA_MASK 0x00ffffff +#define B_INSTR 0x14000000 + +#define RET_INSTR 0xd65f03c0 + +#define LDP_STP_MASK 0xffc00000 +#define STP_32 0x29800000 +#define STP_64 0xa9800000 +#define LDP_32 0x28c00000 +#define LDP_64 0xa8c00000 +#define LDP_STP_PREIND (1 << 24) +#define LDP_STP_DIR (1 << 22) /* Load instruction */ +#define ARG1_SHIFT 0 +#define ARG1_MASK 0x1f +#define ARG2_SHIFT 10 +#define ARG2_MASK 0x1f +#define OFFSET_SHIFT 15 +#define OFFSET_SIZE 7 +#define OFFSET_MASK ((1 << OFFSET_SIZE) - 1) + +#define DTRACE_INVOP_PUSHM 1 +#define DTRACE_INVOP_RET 2 +#define DTRACE_INVOP_B 3 #endif diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_asm.S b/sys/cddl/dev/dtrace/aarch64/dtrace_asm.S new file mode 100644 index 000000000000..9ab44993a6e9 --- /dev/null +++ b/sys/cddl/dev/dtrace/aarch64/dtrace_asm.S @@ -0,0 +1,173 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#define _ASM +#define _LOCORE + +#include +#include + +#include +#include + +#include "assym.s" + +/* +void dtrace_membar_producer(void) +*/ +ENTRY(dtrace_membar_producer) + RET +END(dtrace_membar_producer) + +/* +void dtrace_membar_consumer(void) +*/ +ENTRY(dtrace_membar_consumer) + RET +END(dtrace_membar_consumer) + +/* +dtrace_icookie_t dtrace_interrupt_disable(void) +*/ +ENTRY(dtrace_interrupt_disable) + msr daifset, #2 + RET +END(dtrace_interrupt_disable) + +/* +void dtrace_interrupt_enable(dtrace_icookie_t cookie) +*/ +ENTRY(dtrace_interrupt_enable) + msr daifclr, #2 + RET +END(dtrace_interrupt_enable) +/* +uint8_t +dtrace_fuword8_nocheck(void *addr) +*/ +ENTRY(dtrace_fuword8_nocheck) + ldrb w0, [x0] + RET +END(dtrace_fuword8_nocheck) + +/* +uint16_t +dtrace_fuword16_nocheck(void *addr) +*/ +ENTRY(dtrace_fuword16_nocheck) + ldrh w0, [x0] + RET +END(dtrace_fuword16_nocheck) + +/* +uint32_t +dtrace_fuword32_nocheck(void *addr) +*/ +ENTRY(dtrace_fuword32_nocheck) + ldr w0, [x0] + RET +END(dtrace_fuword32_nocheck) + +/* +uint64_t +dtrace_fuword64_nocheck(void *addr) +*/ +ENTRY(dtrace_fuword64_nocheck) + ldr x0, [x0] + RET +END(dtrace_fuword64_nocheck) + +/* +void +dtrace_copy(uintptr_t uaddr, uintptr_t kaddr, size_t size) +*/ +ENTRY(dtrace_copy) + cbz x2, 2f /* If len == 0 then skip loop */ +1: + ldrb w4, [x0], #1 /* Load from uaddr */ + strb w4, [x1], #1 /* Store in kaddr */ + sub x2, x2, #1 /* len-- */ + cbnz x2, 1b +2: + RET +END(dtrace_copy) + +/* +void +dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +XXX: Check for flags? +*/ +ENTRY(dtrace_copystr) + cbz x2, 2f /* If len == 0 then skip loop */ + +1: ldrb w4, [x0], #1 /* Load from uaddr */ + strb w4, [x1], #1 /* Store in kaddr */ + cbz w4, 2f /* If == 0 then break */ + sub x2, x2, #1 /* len-- */ + cbnz x2, 1b +2: + RET +END(dtrace_copystr) + +/* +uintptr_t +dtrace_caller(int aframes) +*/ +ENTRY(dtrace_caller) + mov x0, #-1 + RET +END(dtrace_caller) + +/* +uint32_t +dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) +*/ +ENTRY(dtrace_cas32) +1: ldxr w3, [x0] /* Load target */ + cmp w3, w1 /* Check if *target == cmp */ + bne 2f /* No, return */ + stxr w12, w2, [x0] /* Store new to target */ + cbnz w12, 1b /* Try again if store not succeed */ +2: mov w0, w3 /* Return the value loaded from target */ + RET +END(dtrace_cas32) + +/* +void * +dtrace_casptr(volatile void *target, volatile void *cmp, volatile void *new) +*/ +ENTRY(dtrace_casptr) +1: ldxr x3, [x0] /* Load target */ + cmp x3, x1 /* Check if *target == cmp */ + bne 2f /* No, return */ + stxr w12, x2, [x0] /* Store new to target */ + cbnz w12, 1b /* Try again if store not succeed */ +2: mov x0, x3 /* Return the value loaded from target */ + RET +END(dtrace_casptr) diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c b/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c new file mode 100644 index 000000000000..dcda440e8799 --- /dev/null +++ b/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c @@ -0,0 +1,287 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "regset.h" + +/* + * Wee need some reasonable default to prevent backtrace code + * from wandering too far + */ +#define MAX_FUNCTION_SIZE 0x10000 +#define MAX_PROLOGUE_SIZE 0x100 + +uint8_t dtrace_fuword8_nocheck(void *); +uint16_t dtrace_fuword16_nocheck(void *); +uint32_t dtrace_fuword32_nocheck(void *); +uint64_t dtrace_fuword64_nocheck(void *); + +void +dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, + uint32_t *intrpc) +{ + struct unwind_state state; + int scp_offset; + register_t sp; + int depth; + + depth = 0; + + if (intrpc != 0) { + pcstack[depth++] = (pc_t) intrpc; + } + + aframes++; + + __asm __volatile("mov %0, sp" : "=&r" (sp)); + + state.fp = (uint64_t)__builtin_frame_address(0); + state.sp = sp; + state.pc = (uint64_t)dtrace_getpcstack; + + while (depth < pcstack_limit) { + if (unwind_frame(&state)) + break; + + if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) + break; + + /* + * NB: Unlike some other architectures, we don't need to + * explicitly insert cpu_dtrace_caller as it appears in the + * normal kernel stack trace rather than a special trap frame. + */ + if (aframes > 0) { + aframes--; + } else { + pcstack[depth++] = state.pc; + } + + } + + for (; depth < pcstack_limit; depth++) { + pcstack[depth] = 0; + } +} + +void +dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) +{ + + printf("IMPLEMENT ME: %s\n", __func__); +} + +int +dtrace_getustackdepth(void) +{ + + printf("IMPLEMENT ME: %s\n", __func__); + + return (0); +} + +void +dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) +{ + + printf("IMPLEMENT ME: %s\n", __func__); +} + +/*ARGSUSED*/ +uint64_t +dtrace_getarg(int arg, int aframes) +{ + + printf("IMPLEMENT ME: %s\n", __func__); + + return (0); +} + +int +dtrace_getstackdepth(int aframes) +{ + struct unwind_state state; + int scp_offset; + register_t sp; + int depth; + int done; + + depth = 1; + done = 0; + + __asm __volatile("mov %0, sp" : "=&r" (sp)); + + state.fp = (uint64_t)__builtin_frame_address(0); + state.sp = sp; + state.pc = (uint64_t)dtrace_getstackdepth; + + do { + done = unwind_frame(&state); + if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) + break; + depth++; + } while (!done); + + if (depth < aframes) + return (0); + else + return (depth - aframes); +} + +ulong_t +dtrace_getreg(struct trapframe *rp, uint_t reg) +{ + + printf("IMPLEMENT ME: %s\n", __func__); + + return (0); +} + +static int +dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) +{ + + if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = uaddr; + return (0); + } + + return (1); +} + +void +dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +{ + + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copy(uaddr, kaddr, size); +} + +void +dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, + volatile uint16_t *flags) +{ + + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copy(kaddr, uaddr, size); +} + +void +dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +{ + + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copystr(uaddr, kaddr, size, flags); +} + +void +dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, + volatile uint16_t *flags) +{ + + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copystr(kaddr, uaddr, size, flags); +} + +uint8_t +dtrace_fuword8(void *uaddr) +{ + + if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); + } + + return (dtrace_fuword8_nocheck(uaddr)); +} + +uint16_t +dtrace_fuword16(void *uaddr) +{ + + if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); + } + + return (dtrace_fuword16_nocheck(uaddr)); +} + +uint32_t +dtrace_fuword32(void *uaddr) +{ + + if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); + } + + return (dtrace_fuword32_nocheck(uaddr)); +} + +uint64_t +dtrace_fuword64(void *uaddr) +{ + + if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; + return (0); + } + + return (dtrace_fuword64_nocheck(uaddr)); +} diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c new file mode 100644 index 000000000000..9cf5bc4247cd --- /dev/null +++ b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c @@ -0,0 +1,311 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + * + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern uintptr_t dtrace_in_probe_addr; +extern int dtrace_in_probe; +extern dtrace_id_t dtrace_probeid_error; +extern int (*dtrace_invop_jump_addr)(struct trapframe *); +extern void dtrace_getnanotime(struct timespec *tsp); + +int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t); +void dtrace_invop_init(void); +void dtrace_invop_uninit(void); + +typedef struct dtrace_invop_hdlr { + int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t); + struct dtrace_invop_hdlr *dtih_next; +} dtrace_invop_hdlr_t; + +dtrace_invop_hdlr_t *dtrace_invop_hdlr; + +int +dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) +{ + dtrace_invop_hdlr_t *hdlr; + int rval; + + for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) + if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) + return (rval); + + return (0); +} + + +void +dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) +{ + dtrace_invop_hdlr_t *hdlr; + + hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); + hdlr->dtih_func = func; + hdlr->dtih_next = dtrace_invop_hdlr; + dtrace_invop_hdlr = hdlr; +} + +void +dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) +{ + dtrace_invop_hdlr_t *hdlr, *prev; + + hdlr = dtrace_invop_hdlr; + prev = NULL; + + for (;;) { + if (hdlr == NULL) + panic("attempt to remove non-existent invop handler"); + + if (hdlr->dtih_func == func) + break; + + prev = hdlr; + hdlr = hdlr->dtih_next; + } + + if (prev == NULL) { + ASSERT(dtrace_invop_hdlr == hdlr); + dtrace_invop_hdlr = hdlr->dtih_next; + } else { + ASSERT(dtrace_invop_hdlr != hdlr); + prev->dtih_next = hdlr->dtih_next; + } + + kmem_free(hdlr, 0); +} + +/*ARGSUSED*/ +void +dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) +{ + + printf("IMPLEMENT ME: dtrace_toxic_ranges\n"); +} + +void +dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) +{ + cpuset_t cpus; + + if (cpu == DTRACE_CPUALL) + cpus = all_cpus; + else + CPU_SETOF(cpu, &cpus); + + smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func, + smp_no_rendevous_barrier, arg); +} + +static void +dtrace_sync_func(void) +{ + +} + +void +dtrace_sync(void) +{ + + dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); +} + +/* + * DTrace needs a high resolution time function which can + * be called from a probe context and guaranteed not to have + * instrumented with probes itself. + * + * Returns nanoseconds since boot. + */ +uint64_t +dtrace_gethrtime() +{ + struct timespec curtime; + + nanouptime(&curtime); + + return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); + +} + +uint64_t +dtrace_gethrestime(void) +{ + struct timespec current_time; + + dtrace_getnanotime(¤t_time); + + return (current_time.tv_sec * 1000000000UL + current_time.tv_nsec); +} + +/* Function to handle DTrace traps during probes. See arm64/arm64/trap.c */ +int +dtrace_trap(struct trapframe *frame, u_int type) +{ + /* + * A trap can occur while DTrace executes a probe. Before + * executing the probe, DTrace blocks re-scheduling and sets + * a flag in it's per-cpu flags to indicate that it doesn't + * want to fault. On returning from the probe, the no-fault + * flag is cleared and finally re-scheduling is enabled. + * + * Check if DTrace has enabled 'no-fault' mode: + * + */ + + if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { + /* + * There are only a couple of trap types that are expected. + * All the rest will be handled in the usual way. + */ + switch (type) { + case EXCP_DATA_ABORT: + /* Flag a bad address. */ + cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; + cpu_core[curcpu].cpuc_dtrace_illval = 0; + + /* + * Offset the instruction pointer to the instruction + * following the one causing the fault. + */ + frame->tf_elr += 4; + return (1); + default: + /* Handle all other traps in the usual way. */ + break; + } + } + + /* Handle the trap in the usual way. */ + return (0); +} + +void +dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, + int fault, int fltoffs, uintptr_t illval) +{ + + dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, + (uintptr_t)epid, + (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); +} + +static int +dtrace_invop_start(struct trapframe *frame) +{ + int data, invop, reg, update_sp; + register_t arg1, arg2; + register_t *sp; + int offs; + int tmp; + int i; + + invop = dtrace_invop(frame->tf_elr, (uintptr_t *)frame, frame->tf_elr); + + tmp = (invop & LDP_STP_MASK); + if (tmp == STP_64 || tmp == LDP_64) { + sp = (register_t *)frame->tf_sp; + data = invop; + arg1 = (data >> ARG1_SHIFT) & ARG1_MASK; + arg2 = (data >> ARG2_SHIFT) & ARG2_MASK; + + offs = (data >> OFFSET_SHIFT) & OFFSET_MASK; + + switch (tmp) { + case STP_64: + if (offs >> (OFFSET_SIZE - 1)) + sp -= (~offs & OFFSET_MASK) + 1; + else + sp += (offs); + *(sp + 0) = frame->tf_x[arg1]; + *(sp + 1) = frame->tf_x[arg2]; + break; + case LDP_64: + frame->tf_x[arg1] = *(sp + 0); + frame->tf_x[arg2] = *(sp + 1); + if (offs >> (OFFSET_SIZE - 1)) + sp -= (~offs & OFFSET_MASK) + 1; + else + sp += (offs); + break; + default: + break; + } + + /* Update the stack pointer and program counter to continue */ + frame->tf_sp = (register_t)sp; + frame->tf_elr += INSN_SIZE; + return (0); + } + + if ((invop & B_MASK) == B_INSTR) { + data = (invop & B_DATA_MASK); + /* The data is the number of 4-byte words to change the pc */ + data *= 4; + frame->tf_elr += data; + return (0); + } + + if (invop == RET_INSTR) { + frame->tf_elr = frame->tf_lr; + return (0); + } + + return (-1); +} + +void +dtrace_invop_init(void) +{ + + dtrace_invop_jump_addr = dtrace_invop_start; +} + +void +dtrace_invop_uninit(void) +{ + + dtrace_invop_jump_addr = 0; +} diff --git a/sys/cddl/dev/dtrace/aarch64/regset.h b/sys/cddl/dev/dtrace/aarch64/regset.h new file mode 100644 index 000000000000..f99b48f8354f --- /dev/null +++ b/sys/cddl/dev/dtrace/aarch64/regset.h @@ -0,0 +1,51 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _REGSET_H +#define _REGSET_H + +/* + * #pragma ident "@(#)regset.h 1.11 05/06/08 SMI" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Place here */ + +#ifdef __cplusplus +} +#endif + +#endif /* _REGSET_H */ diff --git a/sys/cddl/dev/fbt/aarch64/fbt_isa.c b/sys/cddl/dev/fbt/aarch64/fbt_isa.c new file mode 100644 index 000000000000..94de1e85904c --- /dev/null +++ b/sys/cddl/dev/fbt/aarch64/fbt_isa.c @@ -0,0 +1,180 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Portions Copyright 2006-2008 John Birrell jb@freebsd.org + * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org + * Portions Copyright 2013 Howard Su howardsu@freebsd.org + * Portions Copyright 2015 Ruslan Bukin + * + * $FreeBSD$ + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include + +#include + +#include "fbt.h" + +#define AARCH64_BRK 0xd4200000 +#define AARCH64_BRK_IMM16_SHIFT 5 +#define AARCH64_BRK_IMM16_VAL (0x40d << AARCH64_BRK_IMM16_SHIFT) +#define FBT_PATCHVAL (AARCH64_BRK | AARCH64_BRK_IMM16_VAL) +#define FBT_ENTRY "entry" +#define FBT_RETURN "return" + +int +fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) +{ + struct trapframe *frame; + solaris_cpu_t *cpu; + fbt_probe_t *fbt; + + frame = (struct trapframe *)stack; + cpu = &solaris_cpu[curcpu]; + fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; + + for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { + if ((uintptr_t)fbt->fbtp_patchpoint == addr) { + fbt->fbtp_invop_cnt++; + cpu->cpu_dtrace_caller = addr; + + dtrace_probe(fbt->fbtp_id, frame->tf_x[0], + frame->tf_x[1], frame->tf_x[2], + frame->tf_x[3], frame->tf_x[4]); + + cpu->cpu_dtrace_caller = 0; + return (fbt->fbtp_savedval); + } + } + + return (0); +} + +void +fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val) +{ + + *fbt->fbtp_patchpoint = val; + cpu_icache_sync_range((vm_offset_t)fbt->fbtp_patchpoint, 4); +} + +int +fbt_provide_module_function(linker_file_t lf, int symindx, + linker_symval_t *symval, void *opaque) +{ + fbt_probe_t *fbt, *retfbt; + uint32_t *target, *start; + uint32_t *instr, *limit; + const char *name; + char *modname; + int offs; + + modname = opaque; + name = symval->name; + + /* Check if function is excluded from instrumentation */ + if (fbt_excluded(name)) + return (0); + + instr = (uint32_t *)(symval->value); + limit = (uint32_t *)(symval->value + symval->size); + + /* Look for stp (pre-indexed) operation */ + for (; instr < limit; instr++) { + if ((*instr & LDP_STP_MASK) == STP_64) + break; + } + + if (instr >= limit) + return (0); + + fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); + fbt->fbtp_name = name; + fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, + name, FBT_ENTRY, 3, fbt); + fbt->fbtp_patchpoint = instr; + fbt->fbtp_ctl = lf; + fbt->fbtp_loadcnt = lf->loadcnt; + fbt->fbtp_savedval = *instr; + fbt->fbtp_patchval = FBT_PATCHVAL; + fbt->fbtp_rval = DTRACE_INVOP_PUSHM; + fbt->fbtp_symindx = symindx; + + fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; + fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; + + lf->fbt_nentries++; + + retfbt = NULL; +again: + for (; instr < limit; instr++) { + if (*instr == RET_INSTR) + break; + else if ((*instr & B_MASK) == B_INSTR) { + offs = (*instr & B_DATA_MASK); + offs *= 4; + target = (instr + offs); + start = (uint32_t *)symval->value; + if (target >= limit || target < start) + break; + } + } + + if (instr >= limit) + return (0); + + /* + * We have a winner! + */ + fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); + fbt->fbtp_name = name; + if (retfbt == NULL) { + fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, + name, FBT_RETURN, 3, fbt); + } else { + retfbt->fbtp_next = fbt; + fbt->fbtp_id = retfbt->fbtp_id; + } + retfbt = fbt; + + fbt->fbtp_patchpoint = instr; + fbt->fbtp_ctl = lf; + fbt->fbtp_loadcnt = lf->loadcnt; + fbt->fbtp_symindx = symindx; + if ((*instr & B_MASK) == B_INSTR) + fbt->fbtp_rval = DTRACE_INVOP_B; + else + fbt->fbtp_rval = DTRACE_INVOP_RET; + fbt->fbtp_savedval = *instr; + fbt->fbtp_patchval = FBT_PATCHVAL; + fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; + fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; + + lf->fbt_nentries++; + + instr++; + goto again; +} diff --git a/sys/cddl/dev/fbt/aarch64/fbt_isa.h b/sys/cddl/dev/fbt/aarch64/fbt_isa.h new file mode 100644 index 000000000000..5552f31a64a6 --- /dev/null +++ b/sys/cddl/dev/fbt/aarch64/fbt_isa.h @@ -0,0 +1,30 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + * + */ + +#ifndef _FBT_ISA_H_ +#define _FBT_ISA_H_ + +typedef uint32_t fbt_patchval_t; + +#endif diff --git a/sys/cddl/dev/lockstat/lockstat.c b/sys/cddl/dev/lockstat/lockstat.c index a4e4efd93c58..71a863219b1d 100644 --- a/sys/cddl/dev/lockstat/lockstat.c +++ b/sys/cddl/dev/lockstat/lockstat.c @@ -43,9 +43,8 @@ #include #include -#if defined(__i386__) || defined(__amd64__) || \ - defined(__mips__) || defined(__powerpc__) || \ - defined(__arm__) +#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ + defined(__i386__) || defined(__mips__) || defined(__powerpc__) #define LOCKSTAT_AFRAMES 1 #else #error "architecture not supported" diff --git a/sys/cddl/dev/profile/profile.c b/sys/cddl/dev/profile/profile.c index dd13397aad4e..80a0eca9eaec 100644 --- a/sys/cddl/dev/profile/profile.c +++ b/sys/cddl/dev/profile/profile.c @@ -140,6 +140,11 @@ struct profile_probe_percpu; #define PROF_ARTIFICIAL_FRAMES 10 #endif +#ifdef __aarch64__ +/* TODO: verify */ +#define PROF_ARTIFICIAL_FRAMES 10 +#endif + typedef struct profile_probe { char prof_name[PROF_NAMELEN]; dtrace_id_t prof_id; diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index a32d8d615fc6..bfb271b85dcc 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -66,3 +66,7 @@ libkern/flsl.c standard libkern/flsll.c standard libkern/memmove.c standard libkern/memset.c standard +cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs | dtrace compile-with "${CDDL_C}" +cddl/dev/dtrace/aarch64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}" +cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}" +cddl/dev/fbt/aarch64/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" diff --git a/sys/modules/dtrace/Makefile b/sys/modules/dtrace/Makefile index 94a7a423dfab..d7540d958233 100644 --- a/sys/modules/dtrace/Makefile +++ b/sys/modules/dtrace/Makefile @@ -22,7 +22,7 @@ SUBDIR+= fbt fasttrap .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64" SUBDIR+= systrace_freebsd32 .endif -.if ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" SUBDIR+= fbt .endif .include diff --git a/sys/modules/dtrace/dtraceall/dtraceall.c b/sys/modules/dtrace/dtraceall/dtraceall.c index e06a4826f9b8..ecab4f7fdf82 100644 --- a/sys/modules/dtrace/dtraceall/dtraceall.c +++ b/sys/modules/dtrace/dtraceall/dtraceall.c @@ -69,7 +69,8 @@ MODULE_DEPEND(dtraceall, dtmalloc, 1, 1, 1); #if defined(NFSCL) MODULE_DEPEND(dtraceall, dtnfscl, 1, 1, 1); #endif -#if defined(__amd64__) || defined(__i386__) || defined(__powerpc__) || defined(__arm__) +#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ + defined(__i386__) || defined(__powerpc__) MODULE_DEPEND(dtraceall, fbt, 1, 1, 1); #endif #if defined(__amd64__) || defined(__i386__)