dtrace_subr.c revision 328386
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * $FreeBSD: stable/11/sys/cddl/dev/dtrace/mips/dtrace_subr.c 328386 2018-01-25 02:45:21Z pkelsey $ 23 * 24 */ 25/* 26 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: stable/11/sys/cddl/dev/dtrace/mips/dtrace_subr.c 328386 2018-01-25 02:45:21Z pkelsey $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/types.h> 36#include <sys/kernel.h> 37#include <sys/malloc.h> 38#include <sys/kmem.h> 39#include <sys/smp.h> 40#include <sys/dtrace_impl.h> 41#include <sys/dtrace_bsd.h> 42#include <machine/clock.h> 43#include <machine/frame.h> 44#include <machine/trap.h> 45#include <vm/pmap.h> 46 47#define DELAYBRANCH(x) ((int)(x) < 0) 48 49extern int (*dtrace_invop_jump_addr)(struct trapframe *); 50extern dtrace_id_t dtrace_probeid_error; 51 52int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t); 53 54typedef struct dtrace_invop_hdlr { 55 int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t); 56 struct dtrace_invop_hdlr *dtih_next; 57} dtrace_invop_hdlr_t; 58 59dtrace_invop_hdlr_t *dtrace_invop_hdlr; 60 61int 62dtrace_invop(uintptr_t addr, struct trapframe *stack, uintptr_t eax) 63{ 64 dtrace_invop_hdlr_t *hdlr; 65 int rval; 66 67 for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) 68 if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 69 return (rval); 70 71 return (0); 72} 73 74void 75dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) 76{ 77 dtrace_invop_hdlr_t *hdlr; 78 79 hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); 80 hdlr->dtih_func = func; 81 hdlr->dtih_next = dtrace_invop_hdlr; 82 dtrace_invop_hdlr = hdlr; 83} 84 85void 86dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) 87{ 88 dtrace_invop_hdlr_t *hdlr, *prev; 89 90 hdlr = dtrace_invop_hdlr; 91 prev = NULL; 92 93 for (;;) { 94 if (hdlr == NULL) 95 panic("attempt to remove non-existent invop handler"); 96 97 if (hdlr->dtih_func == func) 98 break; 99 100 prev = hdlr; 101 hdlr = hdlr->dtih_next; 102 } 103 104 if (prev == NULL) { 105 ASSERT(dtrace_invop_hdlr == hdlr); 106 dtrace_invop_hdlr = hdlr->dtih_next; 107 } else { 108 ASSERT(dtrace_invop_hdlr != hdlr); 109 prev->dtih_next = hdlr->dtih_next; 110 } 111 112 kmem_free(hdlr, 0); 113} 114 115/*ARGSUSED*/ 116void 117dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 118{ 119 /* 120 * No toxic regions? 121 */ 122} 123 124void 125dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 126{ 127 cpuset_t cpus; 128 129 if (cpu == DTRACE_CPUALL) 130 cpus = all_cpus; 131 else 132 CPU_SETOF(cpu, &cpus); 133 134 smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, func, 135 smp_no_rendezvous_barrier, arg); 136} 137 138static void 139dtrace_sync_func(void) 140{ 141} 142 143void 144dtrace_sync(void) 145{ 146 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 147} 148 149/* 150 * DTrace needs a high resolution time function which can 151 * be called from a probe context and guaranteed not to have 152 * instrumented with probes itself. 153 * 154 * Returns nanoseconds since boot. 155 */ 156uint64_t 157dtrace_gethrtime() 158{ 159 struct timespec curtime; 160 161 nanouptime(&curtime); 162 163 return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 164 165} 166 167uint64_t 168dtrace_gethrestime(void) 169{ 170 struct timespec curtime; 171 172 getnanotime(&curtime); 173 174 return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 175} 176 177/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ 178int 179dtrace_trap(struct trapframe *frame, u_int type) 180{ 181 182 /* 183 * A trap can occur while DTrace executes a probe. Before 184 * executing the probe, DTrace blocks re-scheduling and sets 185 * a flag in its per-cpu flags to indicate that it doesn't 186 * want to fault. On returning from the probe, the no-fault 187 * flag is cleared and finally re-scheduling is enabled. 188 * 189 * Check if DTrace has enabled 'no-fault' mode: 190 */ 191 if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { 192 /* 193 * There are only a couple of trap types that are expected. 194 * All the rest will be handled in the usual way. 195 */ 196 switch (type) { 197 /* Page fault. */ 198 case T_TLB_ST_MISS: 199 case T_ADDR_ERR_ST: 200 case T_TLB_LD_MISS: 201 case T_ADDR_ERR_LD: 202 case T_BUS_ERR_IFETCH: 203 /* Flag a bad address. */ 204 cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; 205 cpu_core[curcpu].cpuc_dtrace_illval = frame->badvaddr; 206 207 /* 208 * Offset the instruction pointer to the instruction 209 * following the one causing the fault. 210 */ 211 if (DELAYBRANCH(frame->cause)) /* Check BD bit */ 212 { 213 /* XXX: check MipsEmulateBranch on MIPS64 214 frame->pc = MipsEmulateBranch(frame, frame->pc, 215 0, 0); 216 */ 217 panic("%s: delay slot at %jx, badvaddr = %jx\n", 218 __func__, 219 (intmax_t)frame->pc, (intmax_t)frame->badvaddr); 220 } 221 else 222 frame->pc += sizeof(int); 223 return (1); 224 default: 225 /* Handle all other traps in the usual way. */ 226 break; 227 } 228 } 229 230 /* Handle the trap in the usual way. */ 231 return (0); 232} 233 234void 235dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 236 int fault, int fltoffs, uintptr_t illval) 237{ 238 239 dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, 240 (uintptr_t)epid, 241 (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); 242} 243 244static int 245dtrace_invop_start(struct trapframe *frame) 246{ 247 register_t *sp; 248 int16_t offs; 249 int invop; 250 251 invop = dtrace_invop(frame->pc, frame, frame->pc); 252 offs = (invop & LDSD_DATA_MASK); 253 sp = (register_t *)((uint8_t *)frame->sp + offs); 254 255 switch (invop & LDSD_RA_SP_MASK) { 256 case LD_RA_SP: 257 frame->ra = *sp; 258 frame->pc += INSN_SIZE; 259 break; 260 case SD_RA_SP: 261 *(sp) = frame->ra; 262 frame->pc += INSN_SIZE; 263 break; 264 default: 265 printf("%s: 0x%x undefined\n", __func__, invop); 266 return (-1); 267 }; 268 269 return (0); 270} 271 272void 273dtrace_invop_init(void) 274{ 275 276 dtrace_invop_jump_addr = dtrace_invop_start; 277} 278 279void 280dtrace_invop_uninit(void) 281{ 282 283 dtrace_invop_jump_addr = 0; 284} 285