dtrace_subr.c revision 278529
1278529Sgnn/* 2278529Sgnn * CDDL HEADER START 3278529Sgnn * 4278529Sgnn * The contents of this file are subject to the terms of the 5278529Sgnn * Common Development and Distribution License, Version 1.0 only 6278529Sgnn * (the "License"). You may not use this file except in compliance 7278529Sgnn * with the License. 8278529Sgnn * 9278529Sgnn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10278529Sgnn * or http://www.opensolaris.org/os/licensing. 11278529Sgnn * See the License for the specific language governing permissions 12278529Sgnn * and limitations under the License. 13278529Sgnn * 14278529Sgnn * When distributing Covered Code, include this CDDL HEADER in each 15278529Sgnn * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16278529Sgnn * If applicable, add the following below this CDDL HEADER, with the 17278529Sgnn * fields enclosed by brackets "[]" replaced with your own identifying 18278529Sgnn * information: Portions Copyright [yyyy] [name of copyright owner] 19278529Sgnn * 20278529Sgnn * CDDL HEADER END 21278529Sgnn * 22278529Sgnn * $FreeBSD: head/sys/cddl/dev/dtrace/arm/dtrace_subr.c 278529 2015-02-10 19:41:30Z gnn $ 23278529Sgnn * 24278529Sgnn */ 25278529Sgnn/* 26278529Sgnn * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 27278529Sgnn * Use is subject to license terms. 28278529Sgnn */ 29278529Sgnn 30278529Sgnn#include <sys/cdefs.h> 31278529Sgnn__FBSDID("$FreeBSD: head/sys/cddl/dev/dtrace/arm/dtrace_subr.c 278529 2015-02-10 19:41:30Z gnn $"); 32278529Sgnn 33278529Sgnn#include <sys/param.h> 34278529Sgnn#include <sys/systm.h> 35278529Sgnn#include <sys/types.h> 36278529Sgnn#include <sys/kernel.h> 37278529Sgnn#include <sys/malloc.h> 38278529Sgnn#include <sys/kmem.h> 39278529Sgnn#include <sys/smp.h> 40278529Sgnn#include <sys/dtrace_impl.h> 41278529Sgnn#include <sys/dtrace_bsd.h> 42278529Sgnn#include <machine/armreg.h> 43278529Sgnn#include <machine/clock.h> 44278529Sgnn#include <machine/frame.h> 45278529Sgnn#include <machine/trap.h> 46278529Sgnn#include <vm/pmap.h> 47278529Sgnn 48278529Sgnn#define DELAYBRANCH(x) ((int)(x) < 0) 49278529Sgnn 50278529Sgnnextern uintptr_t dtrace_in_probe_addr; 51278529Sgnnextern int dtrace_in_probe; 52278529Sgnnextern dtrace_id_t dtrace_probeid_error; 53278529Sgnnextern int (*dtrace_invop_jump_addr)(struct trapframe *); 54278529Sgnn 55278529Sgnnint dtrace_invop(uintptr_t, uintptr_t *, uintptr_t); 56278529Sgnnvoid dtrace_invop_init(void); 57278529Sgnnvoid dtrace_invop_uninit(void); 58278529Sgnn 59278529Sgnntypedef struct dtrace_invop_hdlr { 60278529Sgnn int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t); 61278529Sgnn struct dtrace_invop_hdlr *dtih_next; 62278529Sgnn} dtrace_invop_hdlr_t; 63278529Sgnn 64278529Sgnndtrace_invop_hdlr_t *dtrace_invop_hdlr; 65278529Sgnn 66278529Sgnnint 67278529Sgnndtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 68278529Sgnn{ 69278529Sgnn dtrace_invop_hdlr_t *hdlr; 70278529Sgnn int rval; 71278529Sgnn 72278529Sgnn for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) 73278529Sgnn if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 74278529Sgnn return (rval); 75278529Sgnn 76278529Sgnn return (0); 77278529Sgnn} 78278529Sgnn 79278529Sgnn 80278529Sgnnvoid 81278529Sgnndtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) 82278529Sgnn{ 83278529Sgnn dtrace_invop_hdlr_t *hdlr; 84278529Sgnn 85278529Sgnn hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); 86278529Sgnn hdlr->dtih_func = func; 87278529Sgnn hdlr->dtih_next = dtrace_invop_hdlr; 88278529Sgnn dtrace_invop_hdlr = hdlr; 89278529Sgnn} 90278529Sgnn 91278529Sgnnvoid 92278529Sgnndtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t)) 93278529Sgnn{ 94278529Sgnn dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL; 95278529Sgnn 96278529Sgnn for (;;) { 97278529Sgnn if (hdlr == NULL) 98278529Sgnn panic("attempt to remove non-existent invop handler"); 99278529Sgnn 100278529Sgnn if (hdlr->dtih_func == func) 101278529Sgnn break; 102278529Sgnn 103278529Sgnn prev = hdlr; 104278529Sgnn hdlr = hdlr->dtih_next; 105278529Sgnn } 106278529Sgnn 107278529Sgnn if (prev == NULL) { 108278529Sgnn ASSERT(dtrace_invop_hdlr == hdlr); 109278529Sgnn dtrace_invop_hdlr = hdlr->dtih_next; 110278529Sgnn } else { 111278529Sgnn ASSERT(dtrace_invop_hdlr != hdlr); 112278529Sgnn prev->dtih_next = hdlr->dtih_next; 113278529Sgnn } 114278529Sgnn 115278529Sgnn kmem_free(hdlr, 0); 116278529Sgnn} 117278529Sgnn 118278529Sgnn 119278529Sgnn/*ARGSUSED*/ 120278529Sgnnvoid 121278529Sgnndtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 122278529Sgnn{ 123278529Sgnn printf("IMPLEMENT ME: dtrace_toxic_ranges\n"); 124278529Sgnn} 125278529Sgnn 126278529Sgnnvoid 127278529Sgnndtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 128278529Sgnn{ 129278529Sgnn cpuset_t cpus; 130278529Sgnn 131278529Sgnn if (cpu == DTRACE_CPUALL) 132278529Sgnn cpus = all_cpus; 133278529Sgnn else 134278529Sgnn CPU_SETOF(cpu, &cpus); 135278529Sgnn 136278529Sgnn smp_rendezvous_cpus(cpus, smp_no_rendevous_barrier, func, 137278529Sgnn smp_no_rendevous_barrier, arg); 138278529Sgnn} 139278529Sgnn 140278529Sgnnstatic void 141278529Sgnndtrace_sync_func(void) 142278529Sgnn{ 143278529Sgnn} 144278529Sgnn 145278529Sgnnvoid 146278529Sgnndtrace_sync(void) 147278529Sgnn{ 148278529Sgnn dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 149278529Sgnn} 150278529Sgnn 151278529Sgnn/* 152278529Sgnn * DTrace needs a high resolution time function which can 153278529Sgnn * be called from a probe context and guaranteed not to have 154278529Sgnn * instrumented with probes itself. 155278529Sgnn * 156278529Sgnn * Returns nanoseconds since boot. 157278529Sgnn */ 158278529Sgnnuint64_t 159278529Sgnndtrace_gethrtime() 160278529Sgnn{ 161278529Sgnn struct timespec curtime; 162278529Sgnn 163278529Sgnn nanouptime(&curtime); 164278529Sgnn 165278529Sgnn return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 166278529Sgnn 167278529Sgnn} 168278529Sgnn 169278529Sgnnuint64_t 170278529Sgnndtrace_gethrestime(void) 171278529Sgnn{ 172278529Sgnn struct timespec curtime; 173278529Sgnn 174278529Sgnn getnanotime(&curtime); 175278529Sgnn 176278529Sgnn return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 177278529Sgnn} 178278529Sgnn 179278529Sgnn/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ 180278529Sgnnint 181278529Sgnndtrace_trap(struct trapframe *frame, u_int type) 182278529Sgnn{ 183278529Sgnn /* 184278529Sgnn * A trap can occur while DTrace executes a probe. Before 185278529Sgnn * executing the probe, DTrace blocks re-scheduling and sets 186278529Sgnn * a flag in it's per-cpu flags to indicate that it doesn't 187278529Sgnn * want to fault. On returning from the probe, the no-fault 188278529Sgnn * flag is cleared and finally re-scheduling is enabled. 189278529Sgnn * 190278529Sgnn * Check if DTrace has enabled 'no-fault' mode: 191278529Sgnn * 192278529Sgnn */ 193278529Sgnn if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { 194278529Sgnn /* 195278529Sgnn * There are only a couple of trap types that are expected. 196278529Sgnn * All the rest will be handled in the usual way. 197278529Sgnn */ 198278529Sgnn switch (type) { 199278529Sgnn /* Page fault. */ 200278529Sgnn case FAULT_ALIGN: 201278529Sgnn /* Flag a bad address. */ 202278529Sgnn cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; 203278529Sgnn cpu_core[curcpu].cpuc_dtrace_illval = 0; 204278529Sgnn 205278529Sgnn /* 206278529Sgnn * Offset the instruction pointer to the instruction 207278529Sgnn * following the one causing the fault. 208278529Sgnn */ 209278529Sgnn frame->tf_pc += sizeof(int); 210278529Sgnn return (1); 211278529Sgnn default: 212278529Sgnn /* Handle all other traps in the usual way. */ 213278529Sgnn break; 214278529Sgnn } 215278529Sgnn } 216278529Sgnn 217278529Sgnn /* Handle the trap in the usual way. */ 218278529Sgnn return (0); 219278529Sgnn} 220278529Sgnn 221278529Sgnnvoid 222278529Sgnndtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 223278529Sgnn int fault, int fltoffs, uintptr_t illval) 224278529Sgnn{ 225278529Sgnn 226278529Sgnn dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, 227278529Sgnn (uintptr_t)epid, 228278529Sgnn (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); 229278529Sgnn} 230278529Sgnn 231278529Sgnnstatic int 232278529Sgnndtrace_invop_start(struct trapframe *frame) 233278529Sgnn{ 234278529Sgnn printf("IMPLEMENT ME: %s\n", __func__); 235278529Sgnn switch (dtrace_invop(frame->tf_pc, (uintptr_t *)frame, frame->tf_pc)) { 236278529Sgnn case DTRACE_INVOP_PUSHM: 237278529Sgnn // TODO: 238278529Sgnn break; 239278529Sgnn case DTRACE_INVOP_POPM: 240278529Sgnn // TODO: 241278529Sgnn break; 242278529Sgnn case DTRACE_INVOP_B: 243278529Sgnn // TODO 244278529Sgnn break; 245278529Sgnn default: 246278529Sgnn return (-1); 247278529Sgnn break; 248278529Sgnn } 249278529Sgnn 250278529Sgnn return (0); 251278529Sgnn} 252278529Sgnn 253278529Sgnnvoid dtrace_invop_init(void) 254278529Sgnn{ 255278529Sgnn dtrace_invop_jump_addr = dtrace_invop_start; 256278529Sgnn} 257278529Sgnn 258278529Sgnnvoid dtrace_invop_uninit(void) 259278529Sgnn{ 260278529Sgnn dtrace_invop_jump_addr = 0; 261278529Sgnn} 262