From 501a9d9525962ad8c39b12d142394c7aa1df0f76 Mon Sep 17 00:00:00 2001
From: br
Date: Tue, 24 May 2016 16:41:37 +0000
Subject: [PATCH] Add initial DTrace support for RISC-V.
Sponsored by: DARPA, AFRL
Sponsored by: HEIF5
---
.../lib/libdtrace/common/dt_link.c | 15 +-
.../lib/libdtrace/common/dt_printf.c | 3 +-
.../lib/libdtrace/riscv/dt_isadep.c | 139 ++++++
cddl/lib/Makefile | 2 +-
cddl/lib/libdtrace/Makefile | 4 +
cddl/usr.sbin/Makefile | 3 +-
.../opensolaris/uts/common/dtrace/dtrace.c | 2 +-
.../opensolaris/uts/common/sys/dtrace.h | 10 +
.../uts/riscv/dtrace/fasttrap_isa.c | 29 ++
.../opensolaris/uts/riscv/sys/fasttrap_isa.h | 46 ++
sys/cddl/dev/dtrace/riscv/dtrace_asm.S | 176 ++++++++
sys/cddl/dev/dtrace/riscv/dtrace_isa.c | 394 ++++++++++++++++++
sys/cddl/dev/dtrace/riscv/dtrace_subr.c | 282 +++++++++++++
sys/cddl/dev/dtrace/riscv/regset.h | 51 +++
sys/cddl/dev/fbt/riscv/fbt_isa.c | 165 ++++++++
sys/cddl/dev/fbt/riscv/fbt_isa.h | 30 ++
sys/cddl/dev/profile/profile.c | 5 +
sys/conf/files.riscv | 4 +
sys/riscv/include/frame.h | 5 +
sys/riscv/include/riscvreg.h | 5 +
sys/riscv/riscv/trap.c | 19 +-
21 files changed, 1383 insertions(+), 6 deletions(-)
create mode 100644 cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c
create mode 100644 sys/cddl/contrib/opensolaris/uts/riscv/dtrace/fasttrap_isa.c
create mode 100644 sys/cddl/contrib/opensolaris/uts/riscv/sys/fasttrap_isa.h
create mode 100644 sys/cddl/dev/dtrace/riscv/dtrace_asm.S
create mode 100644 sys/cddl/dev/dtrace/riscv/dtrace_isa.c
create mode 100644 sys/cddl/dev/dtrace/riscv/dtrace_subr.c
create mode 100644 sys/cddl/dev/dtrace/riscv/regset.h
create mode 100644 sys/cddl/dev/fbt/riscv/fbt_isa.c
create mode 100644 sys/cddl/dev/fbt/riscv/fbt_isa.h
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index f574cf763804..ba5919d9d6b7 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -250,6 +250,9 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
dofr[j].dofr_offset + 4;
rel->r_info = ELF32_R_INFO(count + dep->de_global,
R_PPC_REL32);
+#elif defined(__riscv__)
+/* XXX */
+printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#elif defined(__sparc)
/*
* Add 4 bytes to hit the low half of this 64-bit
@@ -440,6 +443,8 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
dofr[j].dofr_offset;
rel->r_info = ELF64_R_INFO(count + dep->de_global,
R_PPC64_REL64);
+#elif defined(__riscv__)
+/* XXX */
#elif defined(__i386) || defined(__amd64)
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
@@ -935,7 +940,15 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
return (0);
}
-
+#elif defined(__riscv__)
+/* 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(__sparc)
#define DT_OP_RET 0x81c7e008
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
index d408aed45199..01659b517a91 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.c
@@ -310,7 +310,8 @@ pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format,
case sizeof (double):
return (dt_printf(dtp, fp, format,
*((double *)addr) / n));
-#if !defined(__arm__) && !defined(__powerpc__) && !defined(__mips__)
+#if !defined(__arm__) && !defined(__powerpc__) && \
+ !defined(__mips__) && !defined(__riscv__)
case sizeof (long double):
return (dt_printf(dtp, fp, format,
*((long double *)addr) / ldn));
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c b/cddl/contrib/opensolaris/lib/libdtrace/riscv/dt_isadep.c
new file mode 100644
index 000000000000..9f5af8570490
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/riscv/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/lib/Makefile b/cddl/lib/Makefile
index 2bfc6c1e1574..9371865ca428 100644
--- a/cddl/lib/Makefile
+++ b/cddl/lib/Makefile
@@ -26,7 +26,7 @@ _libzpool= libzpool
.endif
.endif
-.if ${MACHINE_CPUARCH} != "sparc64" && ${MACHINE_CPUARCH} != "riscv"
+.if ${MACHINE_CPUARCH} != "sparc64"
_drti= drti
_libdtrace= libdtrace
.endif
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
index 642357fca309..080865c44bab 100644
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -95,6 +95,10 @@ CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/mips
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} == "riscv"
+CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/riscv
+.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/riscv
+.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/riscv
.elif ${MACHINE_CPUARCH} == "sparc64"
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/sparc
diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile
index 07dc671639f2..ff96d859f399 100644
--- a/cddl/usr.sbin/Makefile
+++ b/cddl/usr.sbin/Makefile
@@ -26,7 +26,8 @@ _lockstat= lockstat
_plockstat= plockstat
.endif
-.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm"
+.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" || \
+ ${MACHINE_CPUARCH} == "riscv"
_dtrace= dtrace
_lockstat= lockstat
.endif
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index 086d7786b93c..c2cfd820a610 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -12026,7 +12026,7 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
*factor = 1;
#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \
- defined(__mips__) || defined(__powerpc__)
+ defined(__mips__) || defined(__powerpc__) || defined(__riscv__)
/*
* 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 730b42374a86..cd5f4d0d5eed 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
@@ -2495,6 +2495,16 @@ extern void dtrace_helpers_destroy(proc_t *);
#define DTRACE_INVOP_SD 1
#define DTRACE_INVOP_LD 2
+
+#elif defined(__riscv__)
+
+#define SD_RA_SP_MASK 0x1fff07f
+#define SD_RA_SP 0x0113023
+
+#define DTRACE_INVOP_SD 1
+#define DTRACE_INVOP_RET 2
+#define DTRACE_INVOP_NOP 3
+
#endif
#ifdef __cplusplus
diff --git a/sys/cddl/contrib/opensolaris/uts/riscv/dtrace/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/riscv/dtrace/fasttrap_isa.c
new file mode 100644
index 000000000000..17ef0f3a94a7
--- /dev/null
+++ b/sys/cddl/contrib/opensolaris/uts/riscv/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 RISC-V fasttrap code
+ */
diff --git a/sys/cddl/contrib/opensolaris/uts/riscv/sys/fasttrap_isa.h b/sys/cddl/contrib/opensolaris/uts/riscv/sys/fasttrap_isa.h
new file mode 100644
index 000000000000..9d164e4c5bd8
--- /dev/null
+++ b/sys/cddl/contrib/opensolaris/uts/riscv/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 RISC-V fasttrap headers */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FASTTRAP_ISA_H */
diff --git a/sys/cddl/dev/dtrace/riscv/dtrace_asm.S b/sys/cddl/dev/dtrace/riscv/dtrace_asm.S
new file mode 100644
index 000000000000..da2045813e89
--- /dev/null
+++ b/sys/cddl/dev/dtrace/riscv/dtrace_asm.S
@@ -0,0 +1,176 @@
+/*
+ * 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
+ *
+ * Portions Copyright 2016 Ruslan Bukin
+ *
+ * $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)
+ csrci sstatus, 1
+ RET
+END(dtrace_interrupt_disable)
+
+/*
+void dtrace_interrupt_enable(dtrace_icookie_t cookie)
+*/
+ENTRY(dtrace_interrupt_enable)
+ csrsi sstatus, 1
+ RET
+END(dtrace_interrupt_enable)
+/*
+uint8_t
+dtrace_fuword8_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword8_nocheck)
+ lb a0, 0(a0)
+ RET
+END(dtrace_fuword8_nocheck)
+
+/*
+uint16_t
+dtrace_fuword16_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword16_nocheck)
+ lh a0, 0(a0)
+ RET
+END(dtrace_fuword16_nocheck)
+
+/*
+uint32_t
+dtrace_fuword32_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword32_nocheck)
+ lw a0, 0(a0)
+ RET
+END(dtrace_fuword32_nocheck)
+
+/*
+uint64_t
+dtrace_fuword64_nocheck(void *addr)
+*/
+ENTRY(dtrace_fuword64_nocheck)
+ ld a0, 0(a0)
+ RET
+END(dtrace_fuword64_nocheck)
+
+/*
+void
+dtrace_copy(uintptr_t uaddr, uintptr_t kaddr, size_t size)
+*/
+ENTRY(dtrace_copy)
+ beqz a2, 2f /* If len == 0 then skip loop */
+1:
+ lb a4, 0(a0) /* Load from uaddr */
+ addi a0, a0, 1
+ sb a4, 0(a1) /* Store in kaddr */
+ addi a1, a1, 1
+ addi a2, a2, -1 /* len-- */
+ bnez a2, 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)
+ beqz a2, 2f /* If len == 0 then skip loop */
+ lb a4, 0(a0) /* Load from uaddr */
+ addi a0, a0, 1
+ sb a4, 0(a1) /* Store in kaddr */
+ addi a1, a1, 1
+ beqz a4, 2f /* If == 0 then break */
+ addi a2, a2, -1 /* len-- */
+ bnez a2, 1b
+2:
+ RET
+END(dtrace_copystr)
+
+/*
+uintptr_t
+dtrace_caller(int aframes)
+*/
+ENTRY(dtrace_caller)
+ li a0, -1
+ RET
+END(dtrace_caller)
+
+/*
+uint32_t
+dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
+*/
+ENTRY(dtrace_cas32)
+1: lr.w a3, 0(a0) /* Load target */
+ bne a3, a1, 2f /* *target != cmp ? return */
+ sc.w a4, a2, 0(a0) /* Store new to target */
+ bnez a4, 1b /* Try again if store not succeed */
+2: mv a0, a3 /* 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: lr.d a3, 0(a0) /* Load target */
+ bne a3, a1, 2f /* *target != cmp ? return */
+ sc.d a4, a2, 0(a0) /* Store new to target */
+ bnez a4, 1b /* Try again if store not succeed */
+2: mv a0, a3 /* Return the value loaded from target */
+ RET
+END(dtrace_casptr)
diff --git a/sys/cddl/dev/dtrace/riscv/dtrace_isa.c b/sys/cddl/dev/dtrace/riscv/dtrace_isa.c
new file mode 100644
index 000000000000..955d2cb10f65
--- /dev/null
+++ b/sys/cddl/dev/dtrace/riscv/dtrace_isa.c
@@ -0,0 +1,394 @@
+/*
+ * 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
+ *
+ * Portions Copyright 2016 Ruslan Bukin
+ *
+ * $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 "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
+#define MAX_USTACK_DEPTH 2048
+
+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("mv %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;
+ }
+}
+
+static int
+dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc,
+ uintptr_t fp)
+{
+ volatile uint16_t *flags;
+ uintptr_t oldfp;
+ int ret;
+
+ ret = 0;
+ flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
+
+ ASSERT(pcstack == NULL || pcstack_limit > 0);
+
+ while (pc != 0) {
+ /*
+ * We limit the number of times we can go around this
+ * loop to account for a circular stack.
+ */
+ if (ret++ >= MAX_USTACK_DEPTH) {
+ *flags |= CPU_DTRACE_BADSTACK;
+ cpu_core[curcpu].cpuc_dtrace_illval = fp;
+ break;
+ }
+
+ if (pcstack != NULL) {
+ *pcstack++ = (uint64_t)pc;
+ pcstack_limit--;
+ if (pcstack_limit <= 0)
+ break;
+ }
+
+ if (fp == 0)
+ break;
+
+ pc = dtrace_fuword64((void *)(fp +
+ offsetof(struct riscv_frame, f_retaddr)));
+ fp = dtrace_fuword64((void *)fp);
+
+ if (fp == oldfp) {
+ *flags |= CPU_DTRACE_BADSTACK;
+ cpu_core[curcpu].cpuc_dtrace_illval = fp;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+void
+dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
+{
+ volatile uint16_t *flags;
+ struct trapframe *tf;
+ uintptr_t pc, sp, fp;
+ proc_t *p;
+ int n;
+
+ p = curproc;
+ flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags;
+
+ if (*flags & CPU_DTRACE_FAULT)
+ return;
+
+ if (pcstack_limit <= 0)
+ return;
+
+ /*
+ * If there's no user context we still need to zero the stack.
+ */
+ if (p == NULL || (tf = curthread->td_frame) == NULL)
+ goto zero;
+
+ *pcstack++ = (uint64_t)p->p_pid;
+ pcstack_limit--;
+
+ if (pcstack_limit <= 0)
+ return;
+
+ pc = tf->tf_sepc;
+ sp = tf->tf_sp;
+ fp = tf->tf_s[0];
+
+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) {
+ /*
+ * In an entry probe. The frame pointer has not yet been
+ * pushed (that happens in the function prologue). The
+ * best approach is to add the current pc as a missing top
+ * of stack and back the pc up to the caller, which is stored
+ * at the current stack pointer address since the call
+ * instruction puts it there right before the branch.
+ */
+
+ *pcstack++ = (uint64_t)pc;
+ pcstack_limit--;
+ if (pcstack_limit <= 0)
+ return;
+
+ pc = tf->tf_ra;
+ }
+
+ n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp);
+ ASSERT(n >= 0);
+ ASSERT(n <= pcstack_limit);
+
+ pcstack += n;
+ pcstack_limit -= n;
+
+zero:
+ while (pcstack_limit-- > 0)
+ *pcstack++ = 0;
+}
+
+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("mv %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/riscv/dtrace_subr.c b/sys/cddl/dev/dtrace/riscv/dtrace_subr.c
new file mode 100644
index 000000000000..90d15fc1e0d5
--- /dev/null
+++ b/sys/cddl/dev/dtrace/riscv/dtrace_subr.c
@@ -0,0 +1,282 @@
+/*
+ * 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
+ *
+ * Portions Copyright 2016 Ruslan Bukin
+ *
+ * $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
+#include
+#include
+
+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, struct trapframe *, uintptr_t);
+void dtrace_invop_init(void);
+void dtrace_invop_uninit(void);
+
+typedef struct dtrace_invop_hdlr {
+ int (*dtih_func)(uintptr_t, struct trapframe *, 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, struct trapframe *frame, 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, frame, eax)) != 0)
+ return (rval);
+
+ return (0);
+}
+
+
+void
+dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, 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, struct trapframe *, 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))
+{
+
+ (*func)(0, (uintptr_t)VM_MIN_KERNEL_ADDRESS);
+}
+
+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 riscv/riscv/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_LOAD_ACCESS_FAULT:
+ case EXCP_STORE_ACCESS_FAULT:
+ case EXCP_INSTR_ACCESS_FAULT:
+ /* 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_sepc += 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;
+ uint32_t imm;
+ InstFmt i;
+ int offs;
+ int tmp;
+
+ invop = dtrace_invop(frame->tf_sepc, frame, frame->tf_sepc);
+
+ if (invop == RISCV_INSN_RET) {
+ frame->tf_sepc = frame->tf_ra;
+ return (0);
+ }
+
+ if ((invop & SD_RA_SP_MASK) == SD_RA_SP) {
+ i.word = invop;
+ imm = i.SType.imm0_4 | (i.SType.imm5_11 << 5);
+ sp = (register_t *)((uint8_t *)frame->tf_sp + imm);
+ *sp = frame->tf_ra;
+ frame->tf_sepc += INSN_SIZE;
+ 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/riscv/regset.h b/sys/cddl/dev/dtrace/riscv/regset.h
new file mode 100644
index 000000000000..f99b48f8354f
--- /dev/null
+++ b/sys/cddl/dev/dtrace/riscv/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/riscv/fbt_isa.c b/sys/cddl/dev/fbt/riscv/fbt_isa.c
new file mode 100644
index 000000000000..a8ff9ad92432
--- /dev/null
+++ b/sys/cddl/dev/fbt/riscv/fbt_isa.c
@@ -0,0 +1,165 @@
+/*
+ * 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 2016 Ruslan Bukin
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include
+#include
+
+#include
+
+#include
+
+#include "fbt.h"
+
+#define FBT_PATCHVAL (RISCV_INSN_BREAK)
+#define FBT_ENTRY "entry"
+#define FBT_RETURN "return"
+
+int
+fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
+{
+ solaris_cpu_t *cpu;
+ fbt_probe_t *fbt;
+
+ cpu = &solaris_cpu[curcpu];
+ fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
+
+ for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
+ if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
+ cpu->cpu_dtrace_caller = addr;
+
+ dtrace_probe(fbt->fbtp_id, frame->tf_a[0],
+ frame->tf_a[1], frame->tf_a[2],
+ frame->tf_a[3], frame->tf_a[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 sd operation */
+ for (; instr < limit; instr++) {
+ if ((*instr & SD_RA_SP_MASK) == SD_RA_SP)
+ 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_SD;
+ 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 == RISCV_INSN_RET)
+ 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;
+ 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/riscv/fbt_isa.h b/sys/cddl/dev/fbt/riscv/fbt_isa.h
new file mode 100644
index 000000000000..5552f31a64a6
--- /dev/null
+++ b/sys/cddl/dev/fbt/riscv/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/profile/profile.c b/sys/cddl/dev/profile/profile.c
index 4deac8710dc7..3b584246d14e 100644
--- a/sys/cddl/dev/profile/profile.c
+++ b/sys/cddl/dev/profile/profile.c
@@ -143,6 +143,11 @@ struct profile_probe_percpu;
#define PROF_ARTIFICIAL_FRAMES 10
#endif
+#ifdef __riscv__
+/* 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.riscv b/sys/conf/files.riscv
index 184018522a86..fe30078f183f 100644
--- a/sys/conf/files.riscv
+++ b/sys/conf/files.riscv
@@ -1,4 +1,8 @@
# $FreeBSD$
+cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs | dtrace compile-with "${CDDL_C}"
+cddl/dev/dtrace/riscv/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}"
+cddl/dev/dtrace/riscv/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}"
+cddl/dev/fbt/riscv/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}"
crypto/blowfish/bf_enc.c optional crypto | ipsec
crypto/des/des_enc.c optional crypto | ipsec | netsmb
dev/ofw/ofw_cpu.c optional fdt
diff --git a/sys/riscv/include/frame.h b/sys/riscv/include/frame.h
index e74d9262b355..d0756f757877 100644
--- a/sys/riscv/include/frame.h
+++ b/sys/riscv/include/frame.h
@@ -59,6 +59,11 @@ struct trapframe {
uint64_t tf_scause;
};
+struct riscv_frame {
+ struct riscv_frame *f_frame;
+ u_long f_retaddr;
+};
+
/*
* Signal frame. Pushed onto user stack before calling sigcode.
*/
diff --git a/sys/riscv/include/riscvreg.h b/sys/riscv/include/riscvreg.h
index a71ee47e83fd..6984ab118ab5 100644
--- a/sys/riscv/include/riscvreg.h
+++ b/sys/riscv/include/riscvreg.h
@@ -124,6 +124,11 @@
#define XLEN 8
#define INSN_SIZE 4
+#define INSN_SIZE 4
+#define RISCV_INSN_NOP 0x00000013
+#define RISCV_INSN_BREAK 0x00100073
+#define RISCV_INSN_RET 0x00008067
+
#define CSR_ZIMM(val) \
(__builtin_constant_p(val) && ((u_long)(val) < 32))
diff --git a/sys/riscv/riscv/trap.c b/sys/riscv/riscv/trap.c
index 6327204563f1..22d27f41e592 100644
--- a/sys/riscv/riscv/trap.c
+++ b/sys/riscv/riscv/trap.c
@@ -64,6 +64,12 @@ __FBSDID("$FreeBSD$");
#include
#include
+#ifdef KDTRACE_HOOKS
+#include
+#endif
+
+int (*dtrace_invop_jump_addr)(struct trapframe *);
+
extern register_t fsu_intr_fault;
/* Called from exception.S */
@@ -271,6 +277,11 @@ do_trap_supervisor(struct trapframe *frame)
return;
}
+#ifdef KDTRACE_HOOKS
+ if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, exception))
+ return;
+#endif
+
CTR3(KTR_TRAP, "do_trap_supervisor: curthread: %p, sepc: %lx, frame: %p",
curthread, frame->tf_sepc, frame);
@@ -281,6 +292,12 @@ do_trap_supervisor(struct trapframe *frame)
data_abort(frame, 0);
break;
case EXCP_INSTR_BREAKPOINT:
+#ifdef KDTRACE_HOOKS
+ if (dtrace_invop_jump_addr != 0) {
+ dtrace_invop_jump_addr(frame);
+ break;
+ }
+#endif
#ifdef KDB
kdb_trap(exception, 0, frame);
#else
@@ -290,7 +307,7 @@ do_trap_supervisor(struct trapframe *frame)
break;
case EXCP_INSTR_ILLEGAL:
dump_regs(frame);
- panic("Illegal instruction at %x\n", frame->tf_sepc);
+ panic("Illegal instruction at 0x%016lx\n", frame->tf_sepc);
break;
default:
dump_regs(frame);