dtrace_subr.c revision 1.2.14.1 1 1.2.14.1 bouyer /* $NetBSD: dtrace_subr.c,v 1.2.14.1 2017/04/21 16:52:40 bouyer Exp $ */
2 1.2 ozaki
3 1.1 christos /*
4 1.1 christos * CDDL HEADER START
5 1.1 christos *
6 1.1 christos * The contents of this file are subject to the terms of the
7 1.1 christos * Common Development and Distribution License, Version 1.0 only
8 1.1 christos * (the "License"). You may not use this file except in compliance
9 1.1 christos * with the License.
10 1.1 christos *
11 1.1 christos * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12 1.1 christos * or http://www.opensolaris.org/os/licensing.
13 1.1 christos * See the License for the specific language governing permissions
14 1.1 christos * and limitations under the License.
15 1.1 christos *
16 1.1 christos * When distributing Covered Code, include this CDDL HEADER in each
17 1.1 christos * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18 1.1 christos * If applicable, add the following below this CDDL HEADER, with the
19 1.1 christos * fields enclosed by brackets "[]" replaced with your own identifying
20 1.1 christos * information: Portions Copyright [yyyy] [name of copyright owner]
21 1.1 christos *
22 1.1 christos * CDDL HEADER END
23 1.1 christos *
24 1.1 christos * $FreeBSD$
25 1.1 christos *
26 1.1 christos */
27 1.1 christos /*
28 1.1 christos * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
29 1.1 christos * Use is subject to license terms.
30 1.1 christos */
31 1.1 christos
32 1.1 christos #include <sys/param.h>
33 1.1 christos #include <sys/systm.h>
34 1.1 christos #include <sys/types.h>
35 1.1 christos #include <sys/kernel.h>
36 1.1 christos #include <sys/malloc.h>
37 1.1 christos #include <sys/kmem.h>
38 1.2 ozaki #include <sys/xcall.h>
39 1.2 ozaki #include <sys/cpu.h>
40 1.2 ozaki #include <sys/cpuvar.h>
41 1.1 christos #include <sys/dtrace_impl.h>
42 1.1 christos #include <sys/dtrace_bsd.h>
43 1.2 ozaki #include <machine/cpu.h>
44 1.1 christos #include <machine/frame.h>
45 1.2 ozaki #include <machine/vmparam.h>
46 1.2 ozaki #include <uvm/uvm_pglist.h>
47 1.2 ozaki #include <uvm/uvm_prot.h>
48 1.2 ozaki #include <uvm/uvm_pmap.h>
49 1.1 christos
50 1.2 ozaki extern uintptr_t kernelbase;
51 1.1 christos extern uintptr_t dtrace_in_probe_addr;
52 1.1 christos extern int dtrace_in_probe;
53 1.1 christos extern dtrace_id_t dtrace_probeid_error;
54 1.1 christos
55 1.2.14.1 bouyer int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
56 1.1 christos
57 1.1 christos typedef struct dtrace_invop_hdlr {
58 1.2.14.1 bouyer int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
59 1.1 christos struct dtrace_invop_hdlr *dtih_next;
60 1.1 christos } dtrace_invop_hdlr_t;
61 1.1 christos
62 1.1 christos dtrace_invop_hdlr_t *dtrace_invop_hdlr;
63 1.1 christos
64 1.2 ozaki void dtrace_gethrtime_init(void *arg);
65 1.2 ozaki
66 1.1 christos int
67 1.2.14.1 bouyer dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
68 1.1 christos {
69 1.1 christos dtrace_invop_hdlr_t *hdlr;
70 1.1 christos int rval;
71 1.1 christos
72 1.1 christos for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
73 1.2.14.1 bouyer if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
74 1.1 christos return (rval);
75 1.1 christos
76 1.1 christos return (0);
77 1.1 christos }
78 1.1 christos
79 1.2 ozaki void
80 1.2.14.1 bouyer dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
81 1.2 ozaki {
82 1.2 ozaki dtrace_invop_hdlr_t *hdlr;
83 1.2 ozaki
84 1.2 ozaki hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
85 1.2 ozaki hdlr->dtih_func = func;
86 1.2 ozaki hdlr->dtih_next = dtrace_invop_hdlr;
87 1.2 ozaki dtrace_invop_hdlr = hdlr;
88 1.2 ozaki }
89 1.2 ozaki
90 1.2 ozaki void
91 1.2.14.1 bouyer dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
92 1.2 ozaki {
93 1.2 ozaki dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
94 1.2 ozaki
95 1.2 ozaki for (;;) {
96 1.2 ozaki if (hdlr == NULL)
97 1.2 ozaki panic("attempt to remove non-existent invop handler");
98 1.2 ozaki
99 1.2 ozaki if (hdlr->dtih_func == func)
100 1.2 ozaki break;
101 1.2 ozaki
102 1.2 ozaki prev = hdlr;
103 1.2 ozaki hdlr = hdlr->dtih_next;
104 1.2 ozaki }
105 1.2 ozaki
106 1.2 ozaki if (prev == NULL) {
107 1.2 ozaki ASSERT(dtrace_invop_hdlr == hdlr);
108 1.2 ozaki dtrace_invop_hdlr = hdlr->dtih_next;
109 1.2 ozaki } else {
110 1.2 ozaki ASSERT(dtrace_invop_hdlr != hdlr);
111 1.2 ozaki prev->dtih_next = hdlr->dtih_next;
112 1.2 ozaki }
113 1.2 ozaki
114 1.2 ozaki kmem_free(hdlr, sizeof (dtrace_invop_hdlr_t));
115 1.2 ozaki }
116 1.1 christos
117 1.1 christos void
118 1.1 christos dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
119 1.1 christos {
120 1.2 ozaki (*func)(0, kernelbase);
121 1.2 ozaki }
122 1.2 ozaki
123 1.2 ozaki static void
124 1.2 ozaki xcall_func(void *arg0, void *arg1)
125 1.2 ozaki {
126 1.2 ozaki dtrace_xcall_t func = arg0;
127 1.2 ozaki
128 1.2 ozaki (*func)(arg1);
129 1.1 christos }
130 1.1 christos
131 1.1 christos void
132 1.1 christos dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
133 1.1 christos {
134 1.2 ozaki uint64_t where;
135 1.1 christos
136 1.2 ozaki if (cpu == DTRACE_CPUALL) {
137 1.2 ozaki where = xc_broadcast(0, xcall_func, func, arg);
138 1.2 ozaki } else {
139 1.2 ozaki struct cpu_info *cinfo = cpu_lookup(cpu);
140 1.1 christos
141 1.2 ozaki KASSERT(cinfo != NULL);
142 1.2 ozaki where = xc_unicast(0, xcall_func, func, arg, cinfo);
143 1.2 ozaki }
144 1.2 ozaki xc_wait(where);
145 1.2 ozaki
146 1.2 ozaki /* XXX Q. Do we really need the other cpus to wait also?
147 1.2 ozaki * (see solaris:xc_sync())
148 1.2 ozaki */
149 1.1 christos }
150 1.1 christos
151 1.1 christos static void
152 1.1 christos dtrace_sync_func(void)
153 1.1 christos {
154 1.1 christos }
155 1.1 christos
156 1.1 christos void
157 1.1 christos dtrace_sync(void)
158 1.1 christos {
159 1.1 christos dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
160 1.1 christos }
161 1.1 christos
162 1.1 christos /*
163 1.1 christos * DTrace needs a high resolution time function which can
164 1.1 christos * be called from a probe context and guaranteed not to have
165 1.1 christos * instrumented with probes itself.
166 1.1 christos *
167 1.1 christos * Returns nanoseconds since boot.
168 1.1 christos */
169 1.1 christos uint64_t
170 1.1 christos dtrace_gethrtime()
171 1.1 christos {
172 1.1 christos struct timespec curtime;
173 1.1 christos
174 1.1 christos nanouptime(&curtime);
175 1.1 christos
176 1.1 christos return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
177 1.1 christos
178 1.1 christos }
179 1.1 christos
180 1.1 christos uint64_t
181 1.1 christos dtrace_gethrestime(void)
182 1.1 christos {
183 1.1 christos struct timespec curtime;
184 1.1 christos
185 1.1 christos getnanotime(&curtime);
186 1.1 christos
187 1.1 christos return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
188 1.1 christos }
189 1.1 christos
190 1.2 ozaki /* Function to handle DTrace traps during probes. Not used on ARM yet */
191 1.1 christos int
192 1.1 christos dtrace_trap(struct trapframe *frame, u_int type)
193 1.1 christos {
194 1.2 ozaki cpuid_t cpuid = cpu_number(); /* current cpu id */
195 1.2 ozaki
196 1.1 christos /*
197 1.1 christos * A trap can occur while DTrace executes a probe. Before
198 1.1 christos * executing the probe, DTrace blocks re-scheduling and sets
199 1.1 christos * a flag in it's per-cpu flags to indicate that it doesn't
200 1.1 christos * want to fault. On returning from the probe, the no-fault
201 1.1 christos * flag is cleared and finally re-scheduling is enabled.
202 1.1 christos *
203 1.1 christos * Check if DTrace has enabled 'no-fault' mode:
204 1.1 christos *
205 1.1 christos */
206 1.2 ozaki
207 1.2 ozaki if ((cpu_core[cpuid].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
208 1.1 christos /*
209 1.1 christos * There are only a couple of trap types that are expected.
210 1.1 christos * All the rest will be handled in the usual way.
211 1.1 christos */
212 1.1 christos switch (type) {
213 1.1 christos /* Page fault. */
214 1.1 christos case 0:
215 1.1 christos /* Flag a bad address. */
216 1.2 ozaki cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
217 1.2 ozaki cpu_core[cpuid].cpuc_dtrace_illval = 0;
218 1.1 christos
219 1.1 christos /*
220 1.1 christos * Offset the instruction pointer to the instruction
221 1.1 christos * following the one causing the fault.
222 1.1 christos */
223 1.1 christos panic("%s", __func__);
224 1.1 christos // frame->pc += sizeof(int);
225 1.1 christos return (1);
226 1.1 christos default:
227 1.1 christos /* Handle all other traps in the usual way. */
228 1.1 christos break;
229 1.1 christos }
230 1.1 christos }
231 1.1 christos
232 1.1 christos /* Handle the trap in the usual way. */
233 1.1 christos return (0);
234 1.1 christos }
235 1.1 christos
236 1.1 christos void
237 1.1 christos dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
238 1.1 christos int fault, int fltoffs, uintptr_t illval)
239 1.1 christos {
240 1.1 christos
241 1.1 christos dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
242 1.1 christos (uintptr_t)epid,
243 1.1 christos (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
244 1.1 christos }
245 1.2 ozaki
246 1.2 ozaki void
247 1.2 ozaki dtrace_gethrtime_init(void *arg)
248 1.2 ozaki {
249 1.2 ozaki /* FIXME */
250 1.2 ozaki }
251