1233409Sgonzo/* 2233409Sgonzo * CDDL HEADER START 3233409Sgonzo * 4233409Sgonzo * The contents of this file are subject to the terms of the 5233409Sgonzo * Common Development and Distribution License, Version 1.0 only 6233409Sgonzo * (the "License"). You may not use this file except in compliance 7233409Sgonzo * with the License. 8233409Sgonzo * 9233409Sgonzo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10233409Sgonzo * or http://www.opensolaris.org/os/licensing. 11233409Sgonzo * See the License for the specific language governing permissions 12233409Sgonzo * and limitations under the License. 13233409Sgonzo * 14233409Sgonzo * When distributing Covered Code, include this CDDL HEADER in each 15233409Sgonzo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16233409Sgonzo * If applicable, add the following below this CDDL HEADER, with the 17233409Sgonzo * fields enclosed by brackets "[]" replaced with your own identifying 18233409Sgonzo * information: Portions Copyright [yyyy] [name of copyright owner] 19233409Sgonzo * 20233409Sgonzo * CDDL HEADER END 21233409Sgonzo * 22233409Sgonzo * $FreeBSD$ 23233409Sgonzo * 24233409Sgonzo */ 25233409Sgonzo/* 26233409Sgonzo * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 27233409Sgonzo * Use is subject to license terms. 28233409Sgonzo */ 29233409Sgonzo 30233409Sgonzo#include <sys/cdefs.h> 31233409Sgonzo__FBSDID("$FreeBSD$"); 32233409Sgonzo 33233409Sgonzo#include <sys/param.h> 34233409Sgonzo#include <sys/systm.h> 35233409Sgonzo#include <sys/types.h> 36233409Sgonzo#include <sys/kernel.h> 37233409Sgonzo#include <sys/malloc.h> 38233409Sgonzo#include <sys/kmem.h> 39233409Sgonzo#include <sys/smp.h> 40233409Sgonzo#include <sys/dtrace_impl.h> 41233409Sgonzo#include <sys/dtrace_bsd.h> 42233409Sgonzo#include <machine/clock.h> 43233409Sgonzo#include <machine/frame.h> 44233409Sgonzo#include <machine/trap.h> 45233409Sgonzo#include <vm/pmap.h> 46233409Sgonzo 47233409Sgonzo#define DELAYBRANCH(x) ((int)(x) < 0) 48233409Sgonzo 49233409Sgonzoextern uintptr_t dtrace_in_probe_addr; 50233409Sgonzoextern int dtrace_in_probe; 51233409Sgonzoextern dtrace_id_t dtrace_probeid_error; 52233409Sgonzo 53233409Sgonzoint dtrace_invop(uintptr_t, uintptr_t *, uintptr_t); 54233409Sgonzo 55233409Sgonzotypedef struct dtrace_invop_hdlr { 56233409Sgonzo int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t); 57233409Sgonzo struct dtrace_invop_hdlr *dtih_next; 58233409Sgonzo} dtrace_invop_hdlr_t; 59233409Sgonzo 60233409Sgonzodtrace_invop_hdlr_t *dtrace_invop_hdlr; 61233409Sgonzo 62233409Sgonzoint 63233409Sgonzodtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 64233409Sgonzo{ 65233409Sgonzo dtrace_invop_hdlr_t *hdlr; 66233409Sgonzo int rval; 67233409Sgonzo 68233409Sgonzo for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) 69233409Sgonzo if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 70233409Sgonzo return (rval); 71233409Sgonzo 72233409Sgonzo return (0); 73233409Sgonzo} 74233409Sgonzo 75233409Sgonzo 76233409Sgonzo/*ARGSUSED*/ 77233409Sgonzovoid 78233409Sgonzodtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 79233409Sgonzo{ 80233409Sgonzo /* 81233409Sgonzo * No toxic regions? 82233409Sgonzo */ 83233409Sgonzo} 84233409Sgonzo 85233409Sgonzovoid 86233409Sgonzodtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 87233409Sgonzo{ 88233409Sgonzo cpuset_t cpus; 89233409Sgonzo 90233409Sgonzo if (cpu == DTRACE_CPUALL) 91233409Sgonzo cpus = all_cpus; 92233409Sgonzo else 93233409Sgonzo CPU_SETOF(cpu, &cpus); 94233409Sgonzo 95233409Sgonzo smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func, 96233409Sgonzo smp_no_rendevous_barrier, arg); 97233409Sgonzo} 98233409Sgonzo 99233409Sgonzostatic void 100233409Sgonzodtrace_sync_func(void) 101233409Sgonzo{ 102233409Sgonzo} 103233409Sgonzo 104233409Sgonzovoid 105233409Sgonzodtrace_sync(void) 106233409Sgonzo{ 107233409Sgonzo dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 108233409Sgonzo} 109233409Sgonzo 110233409Sgonzo/* 111233409Sgonzo * DTrace needs a high resolution time function which can 112233409Sgonzo * be called from a probe context and guaranteed not to have 113233409Sgonzo * instrumented with probes itself. 114233409Sgonzo * 115233409Sgonzo * Returns nanoseconds since boot. 116233409Sgonzo */ 117233409Sgonzouint64_t 118233409Sgonzodtrace_gethrtime() 119233409Sgonzo{ 120233409Sgonzo struct timespec curtime; 121233409Sgonzo 122233409Sgonzo nanouptime(&curtime); 123233409Sgonzo 124233409Sgonzo return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 125233409Sgonzo 126233409Sgonzo} 127233409Sgonzo 128233409Sgonzouint64_t 129233409Sgonzodtrace_gethrestime(void) 130233409Sgonzo{ 131233409Sgonzo struct timespec curtime; 132233409Sgonzo 133233409Sgonzo getnanotime(&curtime); 134233409Sgonzo 135233409Sgonzo return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 136233409Sgonzo} 137233409Sgonzo 138233409Sgonzo/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ 139233409Sgonzoint 140233409Sgonzodtrace_trap(struct trapframe *frame, u_int type) 141233409Sgonzo{ 142233409Sgonzo /* 143233409Sgonzo * A trap can occur while DTrace executes a probe. Before 144233409Sgonzo * executing the probe, DTrace blocks re-scheduling and sets 145233409Sgonzo * a flag in it's per-cpu flags to indicate that it doesn't 146233409Sgonzo * want to fault. On returning from the probe, the no-fault 147233409Sgonzo * flag is cleared and finally re-scheduling is enabled. 148233409Sgonzo * 149233409Sgonzo * Check if DTrace has enabled 'no-fault' mode: 150233409Sgonzo * 151233409Sgonzo */ 152233409Sgonzo if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { 153233409Sgonzo /* 154233409Sgonzo * There are only a couple of trap types that are expected. 155233409Sgonzo * All the rest will be handled in the usual way. 156233409Sgonzo */ 157233409Sgonzo switch (type) { 158233409Sgonzo /* Page fault. */ 159233409Sgonzo case T_TLB_ST_MISS: 160233409Sgonzo case T_ADDR_ERR_ST: 161233409Sgonzo case T_TLB_LD_MISS: 162233409Sgonzo case T_ADDR_ERR_LD: 163233409Sgonzo case T_BUS_ERR_IFETCH: 164233409Sgonzo /* Flag a bad address. */ 165233409Sgonzo cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; 166233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = frame->badvaddr; 167233409Sgonzo 168233409Sgonzo /* 169233409Sgonzo * Offset the instruction pointer to the instruction 170233409Sgonzo * following the one causing the fault. 171233409Sgonzo */ 172233409Sgonzo if (DELAYBRANCH(frame->cause)) /* Check BD bit */ 173233409Sgonzo { 174233409Sgonzo /* XXX: check MipsEmulateBranch on MIPS64 175233409Sgonzo frame->pc = MipsEmulateBranch(frame, frame->pc, 176233409Sgonzo 0, 0); 177233409Sgonzo */ 178233409Sgonzo panic("%s: delay slot at %jx, badvaddr = %jx\n", 179233409Sgonzo __func__, 180233409Sgonzo (intmax_t)frame->pc, (intmax_t)frame->badvaddr); 181233409Sgonzo } 182233409Sgonzo else 183233409Sgonzo frame->pc += sizeof(int); 184233409Sgonzo return (1); 185233409Sgonzo default: 186233409Sgonzo /* Handle all other traps in the usual way. */ 187233409Sgonzo break; 188233409Sgonzo } 189233409Sgonzo } 190233409Sgonzo 191233409Sgonzo /* Handle the trap in the usual way. */ 192233409Sgonzo return (0); 193233409Sgonzo} 194233409Sgonzo 195233409Sgonzovoid 196233409Sgonzodtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 197233409Sgonzo int fault, int fltoffs, uintptr_t illval) 198233409Sgonzo{ 199233409Sgonzo 200233409Sgonzo dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, 201233409Sgonzo (uintptr_t)epid, 202233409Sgonzo (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); 203233409Sgonzo} 204