17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5f498645ahl * Common Development and Distribution License (the "License").
6f498645ahl * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
21f498645ahl
227c478bdstevel@tonic-gate/*
23ae115bcmrj * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate#include <sys/dtrace.h>
307c478bdstevel@tonic-gate#include <sys/fasttrap.h>
317c478bdstevel@tonic-gate#include <sys/x_call.h>
327c478bdstevel@tonic-gate#include <sys/atomic.h>
337c478bdstevel@tonic-gate#include <sys/machsystm.h>
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gatestatic void
367c478bdstevel@tonic-gatedtrace_xcall_func(uint64_t arg1, uint64_t arg2)
377c478bdstevel@tonic-gate{
387c478bdstevel@tonic-gate	(*(dtrace_xcall_t)arg1)((void *)(arg2));
397c478bdstevel@tonic-gate}
407c478bdstevel@tonic-gate
417c478bdstevel@tonic-gatevoid
427c478bdstevel@tonic-gatedtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
437c478bdstevel@tonic-gate{
447c478bdstevel@tonic-gate	if (cpu == DTRACE_CPUALL) {
457c478bdstevel@tonic-gate		xc_all(dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
467c478bdstevel@tonic-gate	} else {
477c478bdstevel@tonic-gate		xc_one(cpu, dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
487c478bdstevel@tonic-gate	}
497c478bdstevel@tonic-gate}
507c478bdstevel@tonic-gate
517c478bdstevel@tonic-gate/*ARGSUSED*/
527c478bdstevel@tonic-gatestatic void
537c478bdstevel@tonic-gatedtrace_sync_func(uint64_t arg1, uint64_t arg2)
547c478bdstevel@tonic-gate{
557c478bdstevel@tonic-gate	membar_consumer();
567c478bdstevel@tonic-gate}
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gatevoid
597c478bdstevel@tonic-gatedtrace_sync(void)
607c478bdstevel@tonic-gate{
617c478bdstevel@tonic-gate	membar_producer();
627c478bdstevel@tonic-gate	xc_all(dtrace_sync_func, 0, 0);
637c478bdstevel@tonic-gate}
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gatevoid
667c478bdstevel@tonic-gatedtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
677c478bdstevel@tonic-gate{
687c478bdstevel@tonic-gate	(*func)(PIOMAPBASE, PIOMAPBASE + PIOMAPSIZE);
697c478bdstevel@tonic-gate	(*func)(OFW_START_ADDR, OFW_END_ADDR);
707c478bdstevel@tonic-gate
717c478bdstevel@tonic-gate	if (hole_end > hole_start)
727c478bdstevel@tonic-gate		(*func)((uintptr_t)hole_start, (uintptr_t)hole_end);
737c478bdstevel@tonic-gate}
747c478bdstevel@tonic-gate
757c478bdstevel@tonic-gateint (*dtrace_pid_probe_ptr)(struct regs *);
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gatevoid
787c478bdstevel@tonic-gatedtrace_pid_probe(struct regs *rp)
797c478bdstevel@tonic-gate{
807c478bdstevel@tonic-gate	krwlock_t *rwp = &CPU->cpu_ft_lock;
817c478bdstevel@tonic-gate	uint32_t instr;
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gate	/*
847c478bdstevel@tonic-gate	 * This trap should only be invoked if there's a corresponding
857c478bdstevel@tonic-gate	 * enabled dtrace probe. If there isn't, send SIGILL as though
867c478bdstevel@tonic-gate	 * the process had executed an invalid trap instruction.
877c478bdstevel@tonic-gate	 */
887c478bdstevel@tonic-gate	rw_enter(rwp, RW_READER);
897c478bdstevel@tonic-gate	if (dtrace_pid_probe_ptr != NULL && (*dtrace_pid_probe_ptr)(rp) == 0) {
907c478bdstevel@tonic-gate		rw_exit(rwp);
917c478bdstevel@tonic-gate		return;
927c478bdstevel@tonic-gate	}
937c478bdstevel@tonic-gate	rw_exit(rwp);
947c478bdstevel@tonic-gate
957c478bdstevel@tonic-gate	/*
967c478bdstevel@tonic-gate	 * It is possible that we were preempted after entering the kernel,
977c478bdstevel@tonic-gate	 * and the tracepoint was removed. If it appears that the process hit
987c478bdstevel@tonic-gate	 * our reserved trap instruction, we call send SIGILL just as though
997c478bdstevel@tonic-gate	 * the user had executed an unused trap instruction.
1007c478bdstevel@tonic-gate	 */
1017c478bdstevel@tonic-gate	if (fuword32((void *)rp->r_pc, &instr) != 0 ||
1027c478bdstevel@tonic-gate	    instr == FASTTRAP_INSTR) {
1037c478bdstevel@tonic-gate		sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
1047c478bdstevel@tonic-gate		proc_t *p = curproc;
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gate		sqp->sq_info.si_signo = SIGILL;
1077c478bdstevel@tonic-gate		sqp->sq_info.si_code = ILL_ILLTRP;
1087c478bdstevel@tonic-gate		sqp->sq_info.si_addr = (caddr_t)rp->r_pc;
1097c478bdstevel@tonic-gate		sqp->sq_info.si_trapno = 0x38;
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gate		mutex_enter(&p->p_lock);
1127c478bdstevel@tonic-gate		sigaddqa(p, curthread, sqp);
1137c478bdstevel@tonic-gate		mutex_exit(&p->p_lock);
1147c478bdstevel@tonic-gate		aston(curthread);
1157c478bdstevel@tonic-gate	}
1167c478bdstevel@tonic-gate}
1177c478bdstevel@tonic-gate
1187c478bdstevel@tonic-gateint (*dtrace_return_probe_ptr)(struct regs *);
1197c478bdstevel@tonic-gate
1207c478bdstevel@tonic-gatevoid
1217c478bdstevel@tonic-gatedtrace_return_probe(struct regs *rp)
1227c478bdstevel@tonic-gate{
1237c478bdstevel@tonic-gate	krwlock_t *rwp;
1247c478bdstevel@tonic-gate	uintptr_t npc = curthread->t_dtrace_npc;
1257c478bdstevel@tonic-gate	uint8_t step = curthread->t_dtrace_step;
1267c478bdstevel@tonic-gate	uint8_t ret = curthread->t_dtrace_ret;
1277c478bdstevel@tonic-gate
1287c478bdstevel@tonic-gate	if (curthread->t_dtrace_ast) {
1297c478bdstevel@tonic-gate		aston(curthread);
1307c478bdstevel@tonic-gate		curthread->t_sig_check = 1;
1317c478bdstevel@tonic-gate	}
1327c478bdstevel@tonic-gate
1337c478bdstevel@tonic-gate	/*
1347c478bdstevel@tonic-gate	 * Clear all user tracing flags.
1357c478bdstevel@tonic-gate	 */
1367c478bdstevel@tonic-gate	curthread->t_dtrace_ft = 0;
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gate	/*
1397c478bdstevel@tonic-gate	 * If we weren't expecting to take a return probe trap, kill the
1407c478bdstevel@tonic-gate	 * process as though it had just executed an unassigned trap
1417c478bdstevel@tonic-gate	 * instruction.
1427c478bdstevel@tonic-gate	 */
1437c478bdstevel@tonic-gate	if (step == 0) {
1447c478bdstevel@tonic-gate		tsignal(curthread, SIGILL);
1457c478bdstevel@tonic-gate		return;
1467c478bdstevel@tonic-gate	}
1477c478bdstevel@tonic-gate
1487c478bdstevel@tonic-gate	ASSERT(rp->r_npc == rp->r_pc + 4);
1497c478bdstevel@tonic-gate
1507c478bdstevel@tonic-gate	/*
1517c478bdstevel@tonic-gate	 * If we hit this trap unrelated to a return probe, we're just here
1527c478bdstevel@tonic-gate	 * to reset the AST flag since we deferred a signal until after we
1537c478bdstevel@tonic-gate	 * logically single-stepped the instruction we copied out.
1547c478bdstevel@tonic-gate	 */
1557c478bdstevel@tonic-gate	if (ret == 0) {
1567c478bdstevel@tonic-gate		rp->r_pc = npc;
1577c478bdstevel@tonic-gate		rp->r_npc = npc + 4;
1587c478bdstevel@tonic-gate		return;
1597c478bdstevel@tonic-gate	}
1607c478bdstevel@tonic-gate
1617c478bdstevel@tonic-gate	/*
1627c478bdstevel@tonic-gate	 * We need to wait until after we've called the dtrace_return_probe_ptr
1637c478bdstevel@tonic-gate	 * function pointer to set %pc and %npc.
1647c478bdstevel@tonic-gate	 */
1657c478bdstevel@tonic-gate	rwp = &CPU->cpu_ft_lock;
1667c478bdstevel@tonic-gate	rw_enter(rwp, RW_READER);
1677c478bdstevel@tonic-gate	if (dtrace_return_probe_ptr != NULL)
1687c478bdstevel@tonic-gate		(void) (*dtrace_return_probe_ptr)(rp);
1697c478bdstevel@tonic-gate	rw_exit(rwp);
1707c478bdstevel@tonic-gate	rp->r_pc = npc;
1717c478bdstevel@tonic-gate	rp->r_npc = npc + 4;
1727c478bdstevel@tonic-gate}
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gatevoid
1757c478bdstevel@tonic-gatedtrace_safe_synchronous_signal(void)
1767c478bdstevel@tonic-gate{
1777c478bdstevel@tonic-gate	kthread_t *t = curthread;
1787c478bdstevel@tonic-gate	struct regs *rp = lwptoregs(ttolwp(t));
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gate	ASSERT(t->t_dtrace_on);
1817c478bdstevel@tonic-gate
1827c478bdstevel@tonic-gate	/*
1837c478bdstevel@tonic-gate	 * If we're not actively tracing an instruction, turn off tracing
1847c478bdstevel@tonic-gate	 * flags. If the instruction we copied out caused a synchronous
1857c478bdstevel@tonic-gate	 * trap, reset the pc and npc back to their original values and turn
1867c478bdstevel@tonic-gate	 * off the flags.
1877c478bdstevel@tonic-gate	 */
1887c478bdstevel@tonic-gate	if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
1897c478bdstevel@tonic-gate	    rp->r_npc != t->t_dtrace_astpc) {
1907c478bdstevel@tonic-gate		t->t_dtrace_ft = 0;
1917c478bdstevel@tonic-gate	} else if (rp->r_pc == t->t_dtrace_scrpc) {
1927c478bdstevel@tonic-gate		rp->r_pc = t->t_dtrace_pc;
1937c478bdstevel@tonic-gate		rp->r_npc = t->t_dtrace_npc;
1947c478bdstevel@tonic-gate		t->t_dtrace_ft = 0;
1957c478bdstevel@tonic-gate	}
1967c478bdstevel@tonic-gate}
1977c478bdstevel@tonic-gate
1987c478bdstevel@tonic-gateint
1997c478bdstevel@tonic-gatedtrace_safe_defer_signal(void)
2007c478bdstevel@tonic-gate{
2017c478bdstevel@tonic-gate	kthread_t *t = curthread;
2027c478bdstevel@tonic-gate	struct regs *rp = lwptoregs(ttolwp(t));
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate	ASSERT(t->t_dtrace_on);
2057c478bdstevel@tonic-gate
2067c478bdstevel@tonic-gate	/*
2077c478bdstevel@tonic-gate	 * If we're not actively tracing an instruction, turn off tracing
2087c478bdstevel@tonic-gate	 * flags.
2097c478bdstevel@tonic-gate	 */
2107c478bdstevel@tonic-gate	if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
2117c478bdstevel@tonic-gate	    rp->r_npc != t->t_dtrace_astpc) {
2127c478bdstevel@tonic-gate		t->t_dtrace_ft = 0;
2137c478bdstevel@tonic-gate		return (0);
2147c478bdstevel@tonic-gate	}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate	/*
2177c478bdstevel@tonic-gate	 * Otherwise, make sure we'll return to the kernel after executing
2187c478bdstevel@tonic-gate	 * the instruction we copied out.
2197c478bdstevel@tonic-gate	 */
2207c478bdstevel@tonic-gate	if (!t->t_dtrace_step) {
2217c478bdstevel@tonic-gate		ASSERT(rp->r_pc == t->t_dtrace_scrpc);
2227c478bdstevel@tonic-gate		rp->r_npc = t->t_dtrace_astpc;
2237c478bdstevel@tonic-gate		t->t_dtrace_step = 1;
2247c478bdstevel@tonic-gate	}
2257c478bdstevel@tonic-gate
2267c478bdstevel@tonic-gate	t->t_dtrace_ast = 1;
2277c478bdstevel@tonic-gate
2287c478bdstevel@tonic-gate	return (1);
2297c478bdstevel@tonic-gate}
230ae115bcmrj
231ae115bcmrj/*
232ae115bcmrj * Additional artificial frames for the machine type. For SPARC, we're already
233ae115bcmrj * accounted for, so return 0.
234ae115bcmrj */
235ae115bcmrjint
236ae115bcmrjdtrace_mach_aframes(void)
237ae115bcmrj{
238ae115bcmrj	return (0);
239ae115bcmrj}
240