xref: /openbsd-src/sys/dev/dt/dt_dev.c (revision 8ce4994e236c890eeafedf556546d89348475d7e)
1*8ce4994eSmpi /*	$OpenBSD: dt_dev.c,v 1.42 2024/12/04 09:37:33 mpi Exp $ */
291b2ecf6Smpi 
391b2ecf6Smpi /*
491b2ecf6Smpi  * Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
591b2ecf6Smpi  *
691b2ecf6Smpi  * Permission to use, copy, modify, and distribute this software for any
791b2ecf6Smpi  * purpose with or without fee is hereby granted, provided that the above
891b2ecf6Smpi  * copyright notice and this permission notice appear in all copies.
991b2ecf6Smpi  *
1091b2ecf6Smpi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1191b2ecf6Smpi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1291b2ecf6Smpi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1391b2ecf6Smpi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1491b2ecf6Smpi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1591b2ecf6Smpi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1691b2ecf6Smpi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1791b2ecf6Smpi  */
1891b2ecf6Smpi 
1991b2ecf6Smpi #include <sys/types.h>
2091b2ecf6Smpi #include <sys/systm.h>
2191b2ecf6Smpi #include <sys/param.h>
22c56c27b6Scheloha #include <sys/clockintr.h>
2391b2ecf6Smpi #include <sys/device.h>
24a28bb56fSclaudio #include <sys/exec_elf.h>
2591b2ecf6Smpi #include <sys/malloc.h>
2691b2ecf6Smpi #include <sys/proc.h>
27a28bb56fSclaudio #include <sys/ptrace.h>
2891b2ecf6Smpi 
299d5d5c61Smpi #include <machine/intr.h>
309d5d5c61Smpi 
3191b2ecf6Smpi #include <dev/dt/dtvar.h>
3291b2ecf6Smpi 
3391b2ecf6Smpi /*
34ecfa01e0Smpi  * Number of frames to skip in stack traces.
3591b2ecf6Smpi  *
36ecfa01e0Smpi  * The number of frames required to execute dt(4) profiling code
37ecfa01e0Smpi  * depends on the probe, context, architecture and possibly the
38ecfa01e0Smpi  * compiler.
39ecfa01e0Smpi  *
40ecfa01e0Smpi  * Static probes (tracepoints) are executed in the context of the
41ecfa01e0Smpi  * current thread and only need to skip frames up to the recording
42ecfa01e0Smpi  * function.  For example the syscall provider:
4391b2ecf6Smpi  *
4491b2ecf6Smpi  *	dt_prov_syscall_entry+0x141
4591b2ecf6Smpi  *	syscall+0x205		<--- start here
4691b2ecf6Smpi  *	Xsyscall+0x128
4791b2ecf6Smpi  *
48ecfa01e0Smpi  * Probes executed in their own context, like the profile provider,
49ecfa01e0Smpi  * need to skip the frames of that context which are different for
50ecfa01e0Smpi  * every architecture.  For example the profile provider executed
51ecfa01e0Smpi  * from hardclock(9) on amd64:
5291b2ecf6Smpi  *
5391b2ecf6Smpi  *	dt_prov_profile_enter+0x6e
54ecfa01e0Smpi  *	hardclock+0x1a9
55ecfa01e0Smpi  *	lapic_clockintr+0x3f
56ecfa01e0Smpi  *	Xresume_lapic_ltimer+0x26
57ecfa01e0Smpi  *	acpicpu_idle+0x1d2	<---- start here.
58ecfa01e0Smpi  *	sched_idle+0x225
5991b2ecf6Smpi  *	proc_trampoline+0x1c
6091b2ecf6Smpi  */
61ecfa01e0Smpi #if defined(__amd64__)
62c56c27b6Scheloha #define DT_FA_PROFILE	5
63f6782744Sclaudio #define DT_FA_STATIC	2
64f6782744Sclaudio #elif defined(__i386__)
65c56c27b6Scheloha #define DT_FA_PROFILE	5
66ecfa01e0Smpi #define DT_FA_STATIC	2
67c5d97e14Sclaudio #elif defined(__macppc__)
68c56c27b6Scheloha #define DT_FA_PROFILE  5
69c5d97e14Sclaudio #define DT_FA_STATIC   2
70d6e57b0dSvisa #elif defined(__octeon__)
71d6e57b0dSvisa #define DT_FA_PROFILE	6
72d6e57b0dSvisa #define DT_FA_STATIC	2
73f1ec5211Skettenis #elif defined(__powerpc64__)
74f1ec5211Skettenis #define DT_FA_PROFILE	6
75f1ec5211Skettenis #define DT_FA_STATIC	2
76ecfa01e0Smpi #elif defined(__sparc64__)
77f6782744Sclaudio #define DT_FA_PROFILE	7
78ecfa01e0Smpi #define DT_FA_STATIC	1
7991b2ecf6Smpi #else
80ecfa01e0Smpi #define DT_FA_STATIC	0
81ecfa01e0Smpi #define DT_FA_PROFILE	0
8291b2ecf6Smpi #endif
8391b2ecf6Smpi 
8491b2ecf6Smpi #define DT_EVTRING_SIZE	16	/* # of slots in per PCB event ring */
8591b2ecf6Smpi 
8691b2ecf6Smpi #define DPRINTF(x...) /* nothing */
8791b2ecf6Smpi 
8891b2ecf6Smpi /*
89f5199088Smpi  * Per-CPU Event States
90f5199088Smpi  *
91f5199088Smpi  *  Locks used to protect struct members:
92cc4b6028Smpi  *	r	owned by thread doing read(2)
93f5199088Smpi  *	c	owned by CPU
94f5199088Smpi  *	s	sliced ownership, based on read/write indexes
95cc4b6028Smpi  *	p	written by CPU, read by thread doing read(2)
96f5199088Smpi  */
97f5199088Smpi struct dt_cpubuf {
98f5199088Smpi 	unsigned int		 dc_prod;	/* [r] read index */
99f5199088Smpi 	unsigned int		 dc_cons;	/* [c] write index */
100f5199088Smpi 	struct dt_evt		*dc_ring;	/* [s] ring of event states */
101f5199088Smpi 	unsigned int	 	 dc_inevt;	/* [c] in event already? */
102f5199088Smpi 
103f5199088Smpi 	/* Counters */
104cc4b6028Smpi 	unsigned int		 dc_dropevt;	/* [p] # of events dropped */
105bb6b0345Smpi 	unsigned int		 dc_skiptick;	/* [p] # of ticks skipped */
106bb6b0345Smpi 	unsigned int		 dc_recurevt;	/* [p] # of recursive events */
107f5199088Smpi 	unsigned int		 dc_readevt;	/* [r] # of events read */
108f5199088Smpi };
109f5199088Smpi 
110f5199088Smpi /*
11191b2ecf6Smpi  * Descriptor associated with each program opening /dev/dt.  It is used
11291b2ecf6Smpi  * to keep track of enabled PCBs.
11391b2ecf6Smpi  *
11491b2ecf6Smpi  *  Locks used to protect struct members in this file:
11511c54b09Smvs  *	a	atomic
116b609c616Santon  *	K	kernel lock
117cc4b6028Smpi  *	r	owned by thread doing read(2)
118f5199088Smpi  *	I	invariant after initialization
11991b2ecf6Smpi  */
12091b2ecf6Smpi struct dt_softc {
121b609c616Santon 	SLIST_ENTRY(dt_softc)	 ds_next;	/* [K] descriptor list */
12291b2ecf6Smpi 	int			 ds_unit;	/* [I] D_CLONE unique unit */
12391b2ecf6Smpi 	pid_t			 ds_pid;	/* [I] PID of tracing program */
1249d5d5c61Smpi 	void			*ds_si;		/* [I] to defer wakeup(9) */
12591b2ecf6Smpi 
126b609c616Santon 	struct dt_pcb_list	 ds_pcbs;	/* [K] list of enabled PCBs */
127b609c616Santon 	int			 ds_recording;	/* [K] currently recording? */
128f5199088Smpi 	unsigned int		 ds_evtcnt;	/* [a] # of readable evts */
12991b2ecf6Smpi 
130f5199088Smpi 	struct dt_cpubuf	 ds_cpu[MAXCPUS]; /* [I] Per-cpu event states */
131f5199088Smpi 	unsigned int		 ds_lastcpu;	/* [r] last CPU ring read(2). */
13291b2ecf6Smpi };
13391b2ecf6Smpi 
134b609c616Santon SLIST_HEAD(, dt_softc) dtdev_list;	/* [K] list of open /dev/dt nodes */
13591b2ecf6Smpi 
13691b2ecf6Smpi /*
13791b2ecf6Smpi  * Probes are created during dt_attach() and never modified/freed during
13891b2ecf6Smpi  * the lifetime of the system.  That's why we consider them as [I]mmutable.
13991b2ecf6Smpi  */
14091b2ecf6Smpi unsigned int			dt_nprobes;	/* [I] # of probes available */
14191b2ecf6Smpi SIMPLEQ_HEAD(, dt_probe)	dt_probe_list;	/* [I] list of probes */
14291b2ecf6Smpi 
14391b2ecf6Smpi struct rwlock			dt_lock = RWLOCK_INITIALIZER("dtlk");
144b609c616Santon volatile uint32_t		dt_tracing = 0;	/* [K] # of processes tracing */
14591b2ecf6Smpi 
14611c54b09Smvs int allowdt;					/* [a] */
147a5bcf5abSbluhm 
14891b2ecf6Smpi void	dtattach(struct device *, struct device *, void *);
14991b2ecf6Smpi int	dtopen(dev_t, int, int, struct proc *);
15091b2ecf6Smpi int	dtclose(dev_t, int, int, struct proc *);
15191b2ecf6Smpi int	dtread(dev_t, struct uio *, int);
15291b2ecf6Smpi int	dtioctl(dev_t, u_long, caddr_t, int, struct proc *);
15391b2ecf6Smpi 
15491b2ecf6Smpi struct	dt_softc *dtlookup(int);
155f5199088Smpi struct	dt_softc *dtalloc(void);
156f5199088Smpi void	dtfree(struct dt_softc *);
15791b2ecf6Smpi 
15891b2ecf6Smpi int	dt_ioctl_list_probes(struct dt_softc *, struct dtioc_probe *);
159cd5e5223Sbluhm int	dt_ioctl_get_args(struct dt_softc *, struct dtioc_arg *);
16091b2ecf6Smpi int	dt_ioctl_get_stats(struct dt_softc *, struct dtioc_stat *);
16191b2ecf6Smpi int	dt_ioctl_record_start(struct dt_softc *);
16291b2ecf6Smpi void	dt_ioctl_record_stop(struct dt_softc *);
16391b2ecf6Smpi int	dt_ioctl_probe_enable(struct dt_softc *, struct dtioc_req *);
164840df46fSjasper int	dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *);
165a28bb56fSclaudio int	dt_ioctl_get_auxbase(struct dt_softc *, struct dtioc_getaux *);
16691b2ecf6Smpi 
167f5199088Smpi int	dt_ring_copy(struct dt_cpubuf *, struct uio *, size_t, size_t *);
16891b2ecf6Smpi 
1699d5d5c61Smpi void	dt_wakeup(struct dt_softc *);
1709d5d5c61Smpi void	dt_deferred_wakeup(void *);
1719d5d5c61Smpi 
17291b2ecf6Smpi void
17391b2ecf6Smpi dtattach(struct device *parent, struct device *self, void *aux)
17491b2ecf6Smpi {
17591b2ecf6Smpi 	SLIST_INIT(&dtdev_list);
17691b2ecf6Smpi 	SIMPLEQ_INIT(&dt_probe_list);
17791b2ecf6Smpi 
17891b2ecf6Smpi 	/* Init providers */
17991b2ecf6Smpi 	dt_nprobes += dt_prov_profile_init();
18091b2ecf6Smpi 	dt_nprobes += dt_prov_syscall_init();
18191b2ecf6Smpi 	dt_nprobes += dt_prov_static_init();
182840df46fSjasper #ifdef DDBPROF
183840df46fSjasper 	dt_nprobes += dt_prov_kprobe_init();
184840df46fSjasper #endif
18591b2ecf6Smpi }
18691b2ecf6Smpi 
18791b2ecf6Smpi int
18891b2ecf6Smpi dtopen(dev_t dev, int flags, int mode, struct proc *p)
18991b2ecf6Smpi {
19091b2ecf6Smpi 	struct dt_softc *sc;
19191b2ecf6Smpi 	int unit = minor(dev);
192c4318b75Smpi 
19311c54b09Smvs 	if (atomic_load_int(&allowdt) == 0)
194c4318b75Smpi 		return EPERM;
19591b2ecf6Smpi 
196f5199088Smpi 	sc = dtalloc();
19791b2ecf6Smpi 	if (sc == NULL)
19891b2ecf6Smpi 		return ENOMEM;
19991b2ecf6Smpi 
200c57c5c68Sbluhm 	/* no sleep after this point */
201c57c5c68Sbluhm 	if (dtlookup(unit) != NULL) {
202f5199088Smpi 		dtfree(sc);
203c57c5c68Sbluhm 		return EBUSY;
204c57c5c68Sbluhm 	}
20591b2ecf6Smpi 
20691b2ecf6Smpi 	sc->ds_unit = unit;
20791b2ecf6Smpi 	sc->ds_pid = p->p_p->ps_pid;
20891b2ecf6Smpi 	TAILQ_INIT(&sc->ds_pcbs);
209f5199088Smpi 	sc->ds_lastcpu = 0;
21091b2ecf6Smpi 	sc->ds_evtcnt = 0;
21191b2ecf6Smpi 
21291b2ecf6Smpi 	SLIST_INSERT_HEAD(&dtdev_list, sc, ds_next);
21391b2ecf6Smpi 
21491b2ecf6Smpi 	DPRINTF("dt%d: pid %d open\n", sc->ds_unit, sc->ds_pid);
21591b2ecf6Smpi 
21691b2ecf6Smpi 	return 0;
21791b2ecf6Smpi }
21891b2ecf6Smpi 
21991b2ecf6Smpi int
22091b2ecf6Smpi dtclose(dev_t dev, int flags, int mode, struct proc *p)
22191b2ecf6Smpi {
22291b2ecf6Smpi 	struct dt_softc *sc;
22391b2ecf6Smpi 	int unit = minor(dev);
22491b2ecf6Smpi 
22591b2ecf6Smpi 	sc = dtlookup(unit);
22691b2ecf6Smpi 	KASSERT(sc != NULL);
22791b2ecf6Smpi 
22891b2ecf6Smpi 	DPRINTF("dt%d: pid %d close\n", sc->ds_unit, sc->ds_pid);
22991b2ecf6Smpi 
23091b2ecf6Smpi 	SLIST_REMOVE(&dtdev_list, sc, dt_softc, ds_next);
23191b2ecf6Smpi 	dt_ioctl_record_stop(sc);
23291b2ecf6Smpi 	dt_pcb_purge(&sc->ds_pcbs);
233f5199088Smpi 	dtfree(sc);
23491b2ecf6Smpi 
23591b2ecf6Smpi 	return 0;
23691b2ecf6Smpi }
23791b2ecf6Smpi 
23891b2ecf6Smpi int
23991b2ecf6Smpi dtread(dev_t dev, struct uio *uio, int flags)
24091b2ecf6Smpi {
24191b2ecf6Smpi 	struct dt_softc *sc;
242f5199088Smpi 	struct dt_cpubuf *dc;
243f5199088Smpi 	int i, error = 0, unit = minor(dev);
2449ff65b2bSmpi 	size_t count, max, read = 0;
24591b2ecf6Smpi 
24691b2ecf6Smpi 	sc = dtlookup(unit);
24791b2ecf6Smpi 	KASSERT(sc != NULL);
24891b2ecf6Smpi 
2499ff65b2bSmpi 	max = howmany(uio->uio_resid, sizeof(struct dt_evt));
2509ff65b2bSmpi 	if (max < 1)
25191b2ecf6Smpi 		return (EMSGSIZE);
25291b2ecf6Smpi 
253f5199088Smpi 	while (!atomic_load_int(&sc->ds_evtcnt)) {
254f2e7dc09Sclaudio 		sleep_setup(sc, PWAIT | PCATCH, "dtread");
255f5199088Smpi 		error = sleep_finish(0, !atomic_load_int(&sc->ds_evtcnt));
25691b2ecf6Smpi 		if (error == EINTR || error == ERESTART)
25791b2ecf6Smpi 			break;
25891b2ecf6Smpi 	}
25991b2ecf6Smpi 	if (error)
26091b2ecf6Smpi 		return error;
26191b2ecf6Smpi 
26291b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
263f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
2649ff65b2bSmpi 		count = 0;
265f5199088Smpi 		dc = &sc->ds_cpu[(sc->ds_lastcpu + i) % ncpusfound];
266f5199088Smpi 		error = dt_ring_copy(dc, uio, max, &count);
267baa78d7bSmpi 		if (error && count == 0)
2689ff65b2bSmpi 			break;
2699ff65b2bSmpi 
27091b2ecf6Smpi 		read += count;
2719ff65b2bSmpi 		max -= count;
2729ff65b2bSmpi 		if (max == 0)
27391b2ecf6Smpi 			break;
27491b2ecf6Smpi 	}
275f5199088Smpi 	sc->ds_lastcpu += i % ncpusfound;
27691b2ecf6Smpi 
277f5199088Smpi 	atomic_sub_int(&sc->ds_evtcnt, read);
27891b2ecf6Smpi 
2799ff65b2bSmpi 	return error;
28091b2ecf6Smpi }
28191b2ecf6Smpi 
28291b2ecf6Smpi int
28391b2ecf6Smpi dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
28491b2ecf6Smpi {
28591b2ecf6Smpi 	struct dt_softc *sc;
28691b2ecf6Smpi 	int unit = minor(dev);
28791b2ecf6Smpi 	int on, error = 0;
28891b2ecf6Smpi 
28991b2ecf6Smpi 	sc = dtlookup(unit);
29091b2ecf6Smpi 	KASSERT(sc != NULL);
29191b2ecf6Smpi 
29291b2ecf6Smpi 	switch (cmd) {
29391b2ecf6Smpi 	case DTIOCGPLIST:
29491b2ecf6Smpi 		return dt_ioctl_list_probes(sc, (struct dtioc_probe *)addr);
295cd5e5223Sbluhm 	case DTIOCGARGS:
296cd5e5223Sbluhm 		return dt_ioctl_get_args(sc, (struct dtioc_arg *)addr);
29791b2ecf6Smpi 	case DTIOCGSTATS:
29891b2ecf6Smpi 		return dt_ioctl_get_stats(sc, (struct dtioc_stat *)addr);
29991b2ecf6Smpi 	case DTIOCRECORD:
30091b2ecf6Smpi 	case DTIOCPRBENABLE:
301840df46fSjasper 	case DTIOCPRBDISABLE:
302a28bb56fSclaudio 	case DTIOCGETAUXBASE:
30391b2ecf6Smpi 		/* root only ioctl(2) */
30491b2ecf6Smpi 		break;
30591b2ecf6Smpi 	default:
30691b2ecf6Smpi 		return ENOTTY;
30791b2ecf6Smpi 	}
30891b2ecf6Smpi 
30991b2ecf6Smpi 	if ((error = suser(p)) != 0)
31091b2ecf6Smpi 		return error;
31191b2ecf6Smpi 
31291b2ecf6Smpi 	switch (cmd) {
31391b2ecf6Smpi 	case DTIOCRECORD:
31491b2ecf6Smpi 		on = *(int *)addr;
31591b2ecf6Smpi 		if (on)
31691b2ecf6Smpi 			error = dt_ioctl_record_start(sc);
31791b2ecf6Smpi 		else
31891b2ecf6Smpi 			dt_ioctl_record_stop(sc);
31991b2ecf6Smpi 		break;
32091b2ecf6Smpi 	case DTIOCPRBENABLE:
32191b2ecf6Smpi 		error = dt_ioctl_probe_enable(sc, (struct dtioc_req *)addr);
32291b2ecf6Smpi 		break;
323840df46fSjasper 	case DTIOCPRBDISABLE:
324840df46fSjasper 		error = dt_ioctl_probe_disable(sc, (struct dtioc_req *)addr);
325840df46fSjasper 		break;
326a28bb56fSclaudio 	case DTIOCGETAUXBASE:
327a28bb56fSclaudio 		error = dt_ioctl_get_auxbase(sc, (struct dtioc_getaux *)addr);
328a28bb56fSclaudio 		break;
32991b2ecf6Smpi 	default:
33091b2ecf6Smpi 		KASSERT(0);
33191b2ecf6Smpi 	}
33291b2ecf6Smpi 
33391b2ecf6Smpi 	return error;
33491b2ecf6Smpi }
33591b2ecf6Smpi 
33691b2ecf6Smpi struct dt_softc *
33791b2ecf6Smpi dtlookup(int unit)
33891b2ecf6Smpi {
33991b2ecf6Smpi 	struct dt_softc *sc;
34091b2ecf6Smpi 
34191b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
34291b2ecf6Smpi 
34391b2ecf6Smpi 	SLIST_FOREACH(sc, &dtdev_list, ds_next) {
34491b2ecf6Smpi 		if (sc->ds_unit == unit)
34591b2ecf6Smpi 			break;
34691b2ecf6Smpi 	}
34791b2ecf6Smpi 
34891b2ecf6Smpi 	return sc;
34991b2ecf6Smpi }
35091b2ecf6Smpi 
351f5199088Smpi struct dt_softc *
352f5199088Smpi dtalloc(void)
353f5199088Smpi {
354f5199088Smpi 	struct dt_softc *sc;
355f5199088Smpi 	struct dt_evt *dtev;
356f5199088Smpi 	int i;
357f5199088Smpi 
358f5199088Smpi 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
359f5199088Smpi 	if (sc == NULL)
360f5199088Smpi 		return NULL;
361f5199088Smpi 
362f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
36318b19e82Smpi 		dtev = mallocarray(DT_EVTRING_SIZE, sizeof(*dtev), M_DEVBUF,
364f5199088Smpi 		    M_WAITOK|M_CANFAIL|M_ZERO);
365f5199088Smpi 		if (dtev == NULL)
366f5199088Smpi 			break;
367f5199088Smpi 		sc->ds_cpu[i].dc_ring = dtev;
368f5199088Smpi 	}
369f5199088Smpi 	if (i < ncpusfound) {
370f5199088Smpi 		dtfree(sc);
371f5199088Smpi 		return NULL;
372f5199088Smpi 	}
373f5199088Smpi 
37418b19e82Smpi 	sc->ds_si = softintr_establish(IPL_SOFTCLOCK, dt_deferred_wakeup, sc);
37518b19e82Smpi 	if (sc->ds_si == NULL) {
37618b19e82Smpi 		dtfree(sc);
37718b19e82Smpi 		return NULL;
37818b19e82Smpi 	}
37918b19e82Smpi 
380f5199088Smpi 	return sc;
381f5199088Smpi }
382f5199088Smpi 
383f5199088Smpi void
384f5199088Smpi dtfree(struct dt_softc *sc)
385f5199088Smpi {
386f5199088Smpi 	struct dt_evt *dtev;
387f5199088Smpi 	int i;
388f5199088Smpi 
38918b19e82Smpi 	if (sc->ds_si != NULL)
39018b19e82Smpi 		softintr_disestablish(sc->ds_si);
39118b19e82Smpi 
392f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
393f5199088Smpi 		dtev = sc->ds_cpu[i].dc_ring;
39418b19e82Smpi 		free(dtev, M_DEVBUF, DT_EVTRING_SIZE * sizeof(*dtev));
395f5199088Smpi 	}
396f5199088Smpi 	free(sc, M_DEVBUF, sizeof(*sc));
397f5199088Smpi }
398f5199088Smpi 
39991b2ecf6Smpi int
40091b2ecf6Smpi dt_ioctl_list_probes(struct dt_softc *sc, struct dtioc_probe *dtpr)
40191b2ecf6Smpi {
40291b2ecf6Smpi 	struct dtioc_probe_info info, *dtpi;
40391b2ecf6Smpi 	struct dt_probe *dtp;
40491b2ecf6Smpi 	size_t size;
40591b2ecf6Smpi 	int error = 0;
40691b2ecf6Smpi 
40791b2ecf6Smpi 	size = dtpr->dtpr_size;
408915014bfSmpi 	dtpr->dtpr_size = dt_nprobes * sizeof(*dtpi);
409915014bfSmpi 	if (size == 0)
410915014bfSmpi 		return 0;
411915014bfSmpi 
41291b2ecf6Smpi 	dtpi = dtpr->dtpr_probes;
41391b2ecf6Smpi 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
41491b2ecf6Smpi 		if (size < sizeof(*dtpi)) {
41591b2ecf6Smpi 			error = ENOSPC;
41691b2ecf6Smpi 			break;
41791b2ecf6Smpi 		}
418cd5e5223Sbluhm 		memset(&info, 0, sizeof(info));
41991b2ecf6Smpi 		info.dtpi_pbn = dtp->dtp_pbn;
42023829576Smpi 		info.dtpi_nargs = dtp->dtp_nargs;
42191b2ecf6Smpi 		strlcpy(info.dtpi_prov, dtp->dtp_prov->dtpv_name,
42291b2ecf6Smpi 		    sizeof(info.dtpi_prov));
42391b2ecf6Smpi 		strlcpy(info.dtpi_func, dtp->dtp_func, sizeof(info.dtpi_func));
42491b2ecf6Smpi 		strlcpy(info.dtpi_name, dtp->dtp_name, sizeof(info.dtpi_name));
42591b2ecf6Smpi 		error = copyout(&info, dtpi, sizeof(*dtpi));
42691b2ecf6Smpi 		if (error)
42791b2ecf6Smpi 			break;
42891b2ecf6Smpi 		size -= sizeof(*dtpi);
42991b2ecf6Smpi 		dtpi++;
430cd5e5223Sbluhm 	}
431cd5e5223Sbluhm 
432cd5e5223Sbluhm 	return error;
433cd5e5223Sbluhm }
434cd5e5223Sbluhm 
435cd5e5223Sbluhm int
436cd5e5223Sbluhm dt_ioctl_get_args(struct dt_softc *sc, struct dtioc_arg *dtar)
437cd5e5223Sbluhm {
438cd5e5223Sbluhm 	struct dtioc_arg_info info, *dtai;
439cd5e5223Sbluhm 	struct dt_probe *dtp;
440cd5e5223Sbluhm 	size_t size, n, t;
441cd5e5223Sbluhm 	uint32_t pbn;
442cd5e5223Sbluhm 	int error = 0;
443cd5e5223Sbluhm 
444cd5e5223Sbluhm 	pbn = dtar->dtar_pbn;
445cd5e5223Sbluhm 	if (pbn == 0 || pbn > dt_nprobes)
446cd5e5223Sbluhm 		return EINVAL;
447cd5e5223Sbluhm 
448cd5e5223Sbluhm 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
449cd5e5223Sbluhm 		if (pbn == dtp->dtp_pbn)
450cd5e5223Sbluhm 			break;
451cd5e5223Sbluhm 	}
452cd5e5223Sbluhm 	if (dtp == NULL)
453cd5e5223Sbluhm 		return EINVAL;
454cd5e5223Sbluhm 
455cd5e5223Sbluhm 	if (dtp->dtp_sysnum != 0) {
456cd5e5223Sbluhm 		/* currently not supported for system calls */
457cd5e5223Sbluhm 		dtar->dtar_size = 0;
458cd5e5223Sbluhm 		return 0;
459cd5e5223Sbluhm 	}
460cd5e5223Sbluhm 
461cd5e5223Sbluhm 	size = dtar->dtar_size;
462cd5e5223Sbluhm 	dtar->dtar_size = dtp->dtp_nargs * sizeof(*dtar);
463cd5e5223Sbluhm 	if (size == 0)
464cd5e5223Sbluhm 		return 0;
465cd5e5223Sbluhm 
466cd5e5223Sbluhm 	t = 0;
467cd5e5223Sbluhm 	dtai = dtar->dtar_args;
468cd5e5223Sbluhm 	for (n = 0; n < dtp->dtp_nargs; n++) {
469cd5e5223Sbluhm 		if (size < sizeof(*dtai)) {
470cd5e5223Sbluhm 			error = ENOSPC;
471cd5e5223Sbluhm 			break;
472cd5e5223Sbluhm 		}
473cd5e5223Sbluhm 		if (n >= DTMAXARGTYPES || dtp->dtp_argtype[n] == NULL)
474cd5e5223Sbluhm 			continue;
475cd5e5223Sbluhm 		memset(&info, 0, sizeof(info));
476cd5e5223Sbluhm 		info.dtai_pbn = dtp->dtp_pbn;
477cd5e5223Sbluhm 		info.dtai_argn = t++;
478cd5e5223Sbluhm 		strlcpy(info.dtai_argtype, dtp->dtp_argtype[n],
479cd5e5223Sbluhm 		    sizeof(info.dtai_argtype));
480cd5e5223Sbluhm 		error = copyout(&info, dtai, sizeof(*dtai));
481cd5e5223Sbluhm 		if (error)
482cd5e5223Sbluhm 			break;
483cd5e5223Sbluhm 		size -= sizeof(*dtai);
484cd5e5223Sbluhm 		dtai++;
485cd5e5223Sbluhm 	}
486cd5e5223Sbluhm 	dtar->dtar_size = t * sizeof(*dtar);
48791b2ecf6Smpi 
48891b2ecf6Smpi 	return error;
48991b2ecf6Smpi }
49091b2ecf6Smpi 
49191b2ecf6Smpi int
49291b2ecf6Smpi dt_ioctl_get_stats(struct dt_softc *sc, struct dtioc_stat *dtst)
49391b2ecf6Smpi {
494f5199088Smpi 	struct dt_cpubuf *dc;
495bb6b0345Smpi 	uint64_t readevt, dropevt, skiptick, recurevt;
496f5199088Smpi 	int i;
49791b2ecf6Smpi 
498bb6b0345Smpi 	readevt = dropevt = skiptick = 0;
499f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
500f5199088Smpi 		dc = &sc->ds_cpu[i];
501f5199088Smpi 
502f5199088Smpi 		membar_consumer();
503f5199088Smpi 		dropevt += dc->dc_dropevt;
504bb6b0345Smpi 		skiptick = dc->dc_skiptick;
505bb6b0345Smpi 		recurevt = dc->dc_recurevt;
506f5199088Smpi 		readevt += dc->dc_readevt;
507f5199088Smpi 	}
508f5199088Smpi 
509f5199088Smpi 	dtst->dtst_readevt = readevt;
510f5199088Smpi 	dtst->dtst_dropevt = dropevt;
511bb6b0345Smpi 	dtst->dtst_skiptick = skiptick;
512bb6b0345Smpi 	dtst->dtst_recurevt = recurevt;
51391b2ecf6Smpi 	return 0;
51491b2ecf6Smpi }
51591b2ecf6Smpi 
51691b2ecf6Smpi int
51791b2ecf6Smpi dt_ioctl_record_start(struct dt_softc *sc)
51891b2ecf6Smpi {
519a79ed6b1Scheloha 	uint64_t now;
52091b2ecf6Smpi 	struct dt_pcb *dp;
52191b2ecf6Smpi 
52291b2ecf6Smpi 	if (sc->ds_recording)
52391b2ecf6Smpi 		return EBUSY;
52491b2ecf6Smpi 
52591b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
52691b2ecf6Smpi 	if (TAILQ_EMPTY(&sc->ds_pcbs))
52791b2ecf6Smpi 		return ENOENT;
52891b2ecf6Smpi 
5290e146e1bSvisa 	rw_enter_write(&dt_lock);
530a79ed6b1Scheloha 	now = nsecuptime();
53191b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
53291b2ecf6Smpi 		struct dt_probe *dtp = dp->dp_dtp;
53391b2ecf6Smpi 
53491b2ecf6Smpi 		SMR_SLIST_INSERT_HEAD_LOCKED(&dtp->dtp_pcbs, dp, dp_pnext);
53591b2ecf6Smpi 		dtp->dtp_recording++;
53691b2ecf6Smpi 		dtp->dtp_prov->dtpv_recording++;
537c56c27b6Scheloha 
538c56c27b6Scheloha 		if (dp->dp_nsecs != 0) {
539c56c27b6Scheloha 			clockintr_bind(&dp->dp_clockintr, dp->dp_cpu, dt_clock,
540c56c27b6Scheloha 			    dp);
541a79ed6b1Scheloha 			clockintr_schedule(&dp->dp_clockintr,
542a79ed6b1Scheloha 			    now + dp->dp_nsecs);
543c56c27b6Scheloha 		}
54491b2ecf6Smpi 	}
5450e146e1bSvisa 	rw_exit_write(&dt_lock);
54691b2ecf6Smpi 
54791b2ecf6Smpi 	sc->ds_recording = 1;
54891b2ecf6Smpi 	dt_tracing++;
54991b2ecf6Smpi 
55091b2ecf6Smpi 	return 0;
55191b2ecf6Smpi }
55291b2ecf6Smpi 
55391b2ecf6Smpi void
55491b2ecf6Smpi dt_ioctl_record_stop(struct dt_softc *sc)
55591b2ecf6Smpi {
55691b2ecf6Smpi 	struct dt_pcb *dp;
55791b2ecf6Smpi 
55891b2ecf6Smpi 	if (!sc->ds_recording)
55991b2ecf6Smpi 		return;
56091b2ecf6Smpi 
56191b2ecf6Smpi 	DPRINTF("dt%d: pid %d disable\n", sc->ds_unit, sc->ds_pid);
56291b2ecf6Smpi 
56391b2ecf6Smpi 	dt_tracing--;
56491b2ecf6Smpi 	sc->ds_recording = 0;
56591b2ecf6Smpi 
5660e146e1bSvisa 	rw_enter_write(&dt_lock);
56791b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
56891b2ecf6Smpi 		struct dt_probe *dtp = dp->dp_dtp;
56991b2ecf6Smpi 
570c56c27b6Scheloha 		/*
571c56c27b6Scheloha 		 * Set an execution barrier to ensure the shared
572c56c27b6Scheloha 		 * reference to dp is inactive.
573c56c27b6Scheloha 		 */
574c56c27b6Scheloha 		if (dp->dp_nsecs != 0)
575c56c27b6Scheloha 			clockintr_unbind(&dp->dp_clockintr, CL_BARRIER);
576c56c27b6Scheloha 
57791b2ecf6Smpi 		dtp->dtp_recording--;
57891b2ecf6Smpi 		dtp->dtp_prov->dtpv_recording--;
57991b2ecf6Smpi 		SMR_SLIST_REMOVE_LOCKED(&dtp->dtp_pcbs, dp, dt_pcb, dp_pnext);
58091b2ecf6Smpi 	}
5810e146e1bSvisa 	rw_exit_write(&dt_lock);
5820e146e1bSvisa 
5830e146e1bSvisa 	/* Wait until readers cannot access the PCBs. */
5840e146e1bSvisa 	smr_barrier();
58591b2ecf6Smpi }
58691b2ecf6Smpi 
58791b2ecf6Smpi int
58891b2ecf6Smpi dt_ioctl_probe_enable(struct dt_softc *sc, struct dtioc_req *dtrq)
58991b2ecf6Smpi {
59091b2ecf6Smpi 	struct dt_pcb_list plist;
59191b2ecf6Smpi 	struct dt_probe *dtp;
592*8ce4994eSmpi 	struct dt_pcb *dp;
59391b2ecf6Smpi 	int error;
59491b2ecf6Smpi 
59591b2ecf6Smpi 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
59691b2ecf6Smpi 		if (dtp->dtp_pbn == dtrq->dtrq_pbn)
59791b2ecf6Smpi 			break;
59891b2ecf6Smpi 	}
59991b2ecf6Smpi 	if (dtp == NULL)
60091b2ecf6Smpi 		return ENOENT;
60191b2ecf6Smpi 
602*8ce4994eSmpi 	/* Only allow one probe of each type. */
603*8ce4994eSmpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
604*8ce4994eSmpi 		if (dp->dp_dtp->dtp_pbn == dtrq->dtrq_pbn)
605*8ce4994eSmpi 			return EEXIST;
606*8ce4994eSmpi 	}
607*8ce4994eSmpi 
60891b2ecf6Smpi 	TAILQ_INIT(&plist);
60991b2ecf6Smpi 	error = dtp->dtp_prov->dtpv_alloc(dtp, sc, &plist, dtrq);
61091b2ecf6Smpi 	if (error)
61191b2ecf6Smpi 		return error;
61291b2ecf6Smpi 
61391b2ecf6Smpi 	DPRINTF("dt%d: pid %d enable %u : %b\n", sc->ds_unit, sc->ds_pid,
61491b2ecf6Smpi 	    dtrq->dtrq_pbn, (unsigned int)dtrq->dtrq_evtflags, DTEVT_FLAG_BITS);
61591b2ecf6Smpi 
61691b2ecf6Smpi 	/* Append all PCBs to this instance */
6171e9785c2Sbket 	TAILQ_CONCAT(&sc->ds_pcbs, &plist, dp_snext);
61891b2ecf6Smpi 
61991b2ecf6Smpi 	return 0;
62091b2ecf6Smpi }
62191b2ecf6Smpi 
622840df46fSjasper int
623840df46fSjasper dt_ioctl_probe_disable(struct dt_softc *sc, struct dtioc_req *dtrq)
624840df46fSjasper {
625840df46fSjasper 	struct dt_probe *dtp;
626840df46fSjasper 	int error;
627840df46fSjasper 
628840df46fSjasper 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
629840df46fSjasper 		if (dtp->dtp_pbn == dtrq->dtrq_pbn)
630840df46fSjasper 			break;
631840df46fSjasper 	}
632840df46fSjasper 	if (dtp == NULL)
633840df46fSjasper 		return ENOENT;
634840df46fSjasper 
635840df46fSjasper 	if (dtp->dtp_prov->dtpv_dealloc) {
636840df46fSjasper 		error = dtp->dtp_prov->dtpv_dealloc(dtp, sc, dtrq);
637840df46fSjasper 		if (error)
638840df46fSjasper 			return error;
639840df46fSjasper 	}
640840df46fSjasper 
641840df46fSjasper 	DPRINTF("dt%d: pid %d dealloc\n", sc->ds_unit, sc->ds_pid,
642840df46fSjasper 	    dtrq->dtrq_pbn);
643840df46fSjasper 
644840df46fSjasper 	return 0;
645840df46fSjasper }
646840df46fSjasper 
647a28bb56fSclaudio int
648a28bb56fSclaudio dt_ioctl_get_auxbase(struct dt_softc *sc, struct dtioc_getaux *dtga)
649a28bb56fSclaudio {
650a28bb56fSclaudio 	struct uio uio;
651a28bb56fSclaudio 	struct iovec iov;
652a28bb56fSclaudio 	struct process *pr;
653a28bb56fSclaudio 	struct proc *p = curproc;
654a28bb56fSclaudio 	AuxInfo auxv[ELF_AUX_ENTRIES];
655a28bb56fSclaudio 	int i, error;
656a28bb56fSclaudio 
657a28bb56fSclaudio 	dtga->dtga_auxbase = 0;
658a28bb56fSclaudio 
659a28bb56fSclaudio 	if ((pr = prfind(dtga->dtga_pid)) == NULL)
660a28bb56fSclaudio 		return ESRCH;
661a28bb56fSclaudio 
662a28bb56fSclaudio 	iov.iov_base = auxv;
663a28bb56fSclaudio 	iov.iov_len = sizeof(auxv);
664a28bb56fSclaudio 	uio.uio_iov = &iov;
665a28bb56fSclaudio 	uio.uio_iovcnt = 1;
666a28bb56fSclaudio 	uio.uio_offset = pr->ps_auxinfo;
667a28bb56fSclaudio 	uio.uio_resid = sizeof(auxv);
668a28bb56fSclaudio 	uio.uio_segflg = UIO_SYSSPACE;
669a28bb56fSclaudio 	uio.uio_procp = p;
670a28bb56fSclaudio 	uio.uio_rw = UIO_READ;
671a28bb56fSclaudio 
672a28bb56fSclaudio 	error = process_domem(p, pr, &uio, PT_READ_D);
673a28bb56fSclaudio 	if (error)
674a28bb56fSclaudio 		return error;
675a28bb56fSclaudio 
676a28bb56fSclaudio 	for (i = 0; i < ELF_AUX_ENTRIES; i++)
677a28bb56fSclaudio 		if (auxv[i].au_id == AUX_base)
678a28bb56fSclaudio 			dtga->dtga_auxbase = auxv[i].au_v;
679a28bb56fSclaudio 
680a28bb56fSclaudio 	return 0;
681a28bb56fSclaudio }
682a28bb56fSclaudio 
68391b2ecf6Smpi struct dt_probe *
68491b2ecf6Smpi dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv)
68591b2ecf6Smpi {
68691b2ecf6Smpi 	struct dt_probe *dtp;
68791b2ecf6Smpi 
68891b2ecf6Smpi 	dtp = malloc(sizeof(*dtp), M_DT, M_NOWAIT|M_ZERO);
68991b2ecf6Smpi 	if (dtp == NULL)
69091b2ecf6Smpi 		return NULL;
69191b2ecf6Smpi 
69291b2ecf6Smpi 	SMR_SLIST_INIT(&dtp->dtp_pcbs);
69391b2ecf6Smpi 	dtp->dtp_prov = dtpv;
69491b2ecf6Smpi 	dtp->dtp_func = func;
69591b2ecf6Smpi 	dtp->dtp_name = name;
69691b2ecf6Smpi 	dtp->dtp_sysnum = -1;
697840df46fSjasper 	dtp->dtp_ref = 0;
698840df46fSjasper 
69991b2ecf6Smpi 	return dtp;
70091b2ecf6Smpi }
70191b2ecf6Smpi 
70291b2ecf6Smpi void
70391b2ecf6Smpi dt_dev_register_probe(struct dt_probe *dtp)
70491b2ecf6Smpi {
70591b2ecf6Smpi 	static uint64_t probe_nb;
70691b2ecf6Smpi 
70791b2ecf6Smpi 	dtp->dtp_pbn = ++probe_nb;
70891b2ecf6Smpi 	SIMPLEQ_INSERT_TAIL(&dt_probe_list, dtp, dtp_next);
70991b2ecf6Smpi }
71091b2ecf6Smpi 
71191b2ecf6Smpi struct dt_pcb *
71291b2ecf6Smpi dt_pcb_alloc(struct dt_probe *dtp, struct dt_softc *sc)
71391b2ecf6Smpi {
71491b2ecf6Smpi 	struct dt_pcb *dp;
71591b2ecf6Smpi 
71691b2ecf6Smpi 	dp = malloc(sizeof(*dp), M_DT, M_WAITOK|M_CANFAIL|M_ZERO);
71791b2ecf6Smpi 	if (dp == NULL)
718f5199088Smpi 		return NULL;
71991b2ecf6Smpi 
72091b2ecf6Smpi 	dp->dp_sc = sc;
72191b2ecf6Smpi 	dp->dp_dtp = dtp;
72291b2ecf6Smpi 	return dp;
72391b2ecf6Smpi }
72491b2ecf6Smpi 
72591b2ecf6Smpi void
72691b2ecf6Smpi dt_pcb_free(struct dt_pcb *dp)
72791b2ecf6Smpi {
72891b2ecf6Smpi 	free(dp, M_DT, sizeof(*dp));
72991b2ecf6Smpi }
73091b2ecf6Smpi 
73191b2ecf6Smpi void
73291b2ecf6Smpi dt_pcb_purge(struct dt_pcb_list *plist)
73391b2ecf6Smpi {
73491b2ecf6Smpi 	struct dt_pcb *dp;
73591b2ecf6Smpi 
73691b2ecf6Smpi 	while ((dp = TAILQ_FIRST(plist)) != NULL) {
73791b2ecf6Smpi 		TAILQ_REMOVE(plist, dp, dp_snext);
73891b2ecf6Smpi 		dt_pcb_free(dp);
73991b2ecf6Smpi 	}
74091b2ecf6Smpi }
74191b2ecf6Smpi 
742bb6b0345Smpi void
743bb6b0345Smpi dt_pcb_ring_skiptick(struct dt_pcb *dp, unsigned int skip)
744bb6b0345Smpi {
745bb6b0345Smpi 	struct dt_cpubuf *dc = &dp->dp_sc->ds_cpu[cpu_number()];
746bb6b0345Smpi 
747bb6b0345Smpi 	dc->dc_skiptick += skip;
748bb6b0345Smpi 	membar_producer();
749bb6b0345Smpi }
750bb6b0345Smpi 
75191b2ecf6Smpi /*
75291b2ecf6Smpi  * Get a reference to the next free event state from the ring.
75391b2ecf6Smpi  */
75491b2ecf6Smpi struct dt_evt *
755ecfa01e0Smpi dt_pcb_ring_get(struct dt_pcb *dp, int profiling)
75691b2ecf6Smpi {
75791b2ecf6Smpi 	struct proc *p = curproc;
75891b2ecf6Smpi 	struct dt_evt *dtev;
759f5199088Smpi 	int prod, cons, distance;
760f5199088Smpi 	struct dt_cpubuf *dc = &dp->dp_sc->ds_cpu[cpu_number()];
76191b2ecf6Smpi 
762bb6b0345Smpi 	if (dc->dc_inevt == 1) {
763bb6b0345Smpi 		dc->dc_recurevt++;
764bb6b0345Smpi 		membar_producer();
765f5199088Smpi 		return NULL;
766bb6b0345Smpi 	}
767f5199088Smpi 
768f5199088Smpi 	dc->dc_inevt = 1;
769f5199088Smpi 
770f5199088Smpi 	membar_consumer();
771f5199088Smpi 	prod = dc->dc_prod;
772f5199088Smpi 	cons = dc->dc_cons;
773f5199088Smpi 	distance = prod - cons;
77491b2ecf6Smpi 	if (distance == 1 || distance == (1 - DT_EVTRING_SIZE)) {
77591b2ecf6Smpi 		/* read(2) isn't finished */
776f5199088Smpi 		dc->dc_dropevt++;
777f5199088Smpi 		membar_producer();
778f5199088Smpi 
779f5199088Smpi 		dc->dc_inevt = 0;
78091b2ecf6Smpi 		return NULL;
78191b2ecf6Smpi 	}
78291b2ecf6Smpi 
78391b2ecf6Smpi 	/*
78491b2ecf6Smpi 	 * Save states in next free event slot.
78591b2ecf6Smpi 	 */
786f5199088Smpi 	dtev = &dc->dc_ring[cons];
78791b2ecf6Smpi 	memset(dtev, 0, sizeof(*dtev));
78891b2ecf6Smpi 
78991b2ecf6Smpi 	dtev->dtev_pbn = dp->dp_dtp->dtp_pbn;
79091b2ecf6Smpi 	dtev->dtev_cpu = cpu_number();
79191b2ecf6Smpi 	dtev->dtev_pid = p->p_p->ps_pid;
79221e92265Sbluhm 	dtev->dtev_tid = p->p_tid + THREAD_PID_OFFSET;
79391b2ecf6Smpi 	nanotime(&dtev->dtev_tsp);
79491b2ecf6Smpi 
79591b2ecf6Smpi 	if (ISSET(dp->dp_evtflags, DTEVT_EXECNAME))
79614cb6e73Sderaadt 		strlcpy(dtev->dtev_comm, p->p_p->ps_comm, sizeof(dtev->dtev_comm));
79791b2ecf6Smpi 
798a28bb56fSclaudio 	if (ISSET(dp->dp_evtflags, DTEVT_KSTACK)) {
799ecfa01e0Smpi 		if (profiling)
800ecfa01e0Smpi 			stacktrace_save_at(&dtev->dtev_kstack, DT_FA_PROFILE);
801ecfa01e0Smpi 		else
802ecfa01e0Smpi 			stacktrace_save_at(&dtev->dtev_kstack, DT_FA_STATIC);
80391b2ecf6Smpi 	}
804a28bb56fSclaudio 	if (ISSET(dp->dp_evtflags, DTEVT_USTACK))
805a28bb56fSclaudio 		stacktrace_save_utrace(&dtev->dtev_ustack);
80691b2ecf6Smpi 
80791b2ecf6Smpi 	return dtev;
80891b2ecf6Smpi }
80991b2ecf6Smpi 
81091b2ecf6Smpi void
81191b2ecf6Smpi dt_pcb_ring_consume(struct dt_pcb *dp, struct dt_evt *dtev)
81291b2ecf6Smpi {
813f5199088Smpi 	struct dt_cpubuf *dc = &dp->dp_sc->ds_cpu[cpu_number()];
81491b2ecf6Smpi 
815f5199088Smpi 	KASSERT(dtev == &dc->dc_ring[dc->dc_cons]);
81691b2ecf6Smpi 
817f5199088Smpi 	dc->dc_cons = (dc->dc_cons + 1) % DT_EVTRING_SIZE;
818f5199088Smpi 	membar_producer();
819f5199088Smpi 
820f5199088Smpi 	atomic_inc_int(&dp->dp_sc->ds_evtcnt);
821f5199088Smpi 	dc->dc_inevt = 0;
822f5199088Smpi 
8239d5d5c61Smpi 	dt_wakeup(dp->dp_sc);
82491b2ecf6Smpi }
82591b2ecf6Smpi 
82691b2ecf6Smpi /*
827f5199088Smpi  * Copy at most `max' events from `dc', producing the same amount
82891b2ecf6Smpi  * of free slots.
82991b2ecf6Smpi  */
83091b2ecf6Smpi int
831f5199088Smpi dt_ring_copy(struct dt_cpubuf *dc, struct uio *uio, size_t max, size_t *rcvd)
83291b2ecf6Smpi {
83391b2ecf6Smpi 	size_t count, copied = 0;
83491b2ecf6Smpi 	unsigned int cons, prod;
8359ff65b2bSmpi 	int error = 0;
83691b2ecf6Smpi 
8379ff65b2bSmpi 	KASSERT(max > 0);
83891b2ecf6Smpi 
839f5199088Smpi 	membar_consumer();
840f5199088Smpi 	cons = dc->dc_cons;
841f5199088Smpi 	prod = dc->dc_prod;
84291b2ecf6Smpi 
84391b2ecf6Smpi 	if (cons < prod)
84491b2ecf6Smpi 		count = DT_EVTRING_SIZE - prod;
84591b2ecf6Smpi 	else
84691b2ecf6Smpi 		count = cons - prod;
84791b2ecf6Smpi 
84891b2ecf6Smpi 	if (count == 0)
8499ff65b2bSmpi 		return 0;
85091b2ecf6Smpi 
8519ff65b2bSmpi 	count = MIN(count, max);
852f5199088Smpi 	error = uiomove(&dc->dc_ring[prod], count * sizeof(struct dt_evt), uio);
8539ff65b2bSmpi 	if (error)
8549ff65b2bSmpi 		return error;
85591b2ecf6Smpi 	copied += count;
85691b2ecf6Smpi 
85791b2ecf6Smpi 	/* Produce */
85891b2ecf6Smpi 	prod = (prod + count) % DT_EVTRING_SIZE;
85991b2ecf6Smpi 
8609ff65b2bSmpi 	/* If the ring didn't wrap, stop here. */
8619ff65b2bSmpi 	if (max == copied || prod != 0 || cons == 0)
86291b2ecf6Smpi 		goto out;
86391b2ecf6Smpi 
8649ff65b2bSmpi 	count = MIN(cons, (max - copied));
865f5199088Smpi 	error = uiomove(&dc->dc_ring[0], count * sizeof(struct dt_evt), uio);
8669ff65b2bSmpi 	if (error)
8679ff65b2bSmpi 		goto out;
8689ff65b2bSmpi 
86991b2ecf6Smpi 	copied += count;
87091b2ecf6Smpi 	prod += count;
87191b2ecf6Smpi 
87291b2ecf6Smpi out:
873f5199088Smpi 	dc->dc_readevt += copied;
874f5199088Smpi 	dc->dc_prod = prod;
875f5199088Smpi 	membar_producer();
8769ff65b2bSmpi 
8779ff65b2bSmpi 	*rcvd = copied;
8789ff65b2bSmpi 	return error;
87991b2ecf6Smpi }
8809d5d5c61Smpi 
8819d5d5c61Smpi void
8829d5d5c61Smpi dt_wakeup(struct dt_softc *sc)
8839d5d5c61Smpi {
8849d5d5c61Smpi 	/*
8859d5d5c61Smpi 	 * It is not always safe or possible to call wakeup(9) and grab
8869d5d5c61Smpi 	 * the SCHED_LOCK() from a given tracepoint.  This is true for
8879d5d5c61Smpi 	 * any tracepoint that might trigger inside the scheduler or at
8889d5d5c61Smpi 	 * any IPL higher than IPL_SCHED.  For this reason use a soft-
8899d5d5c61Smpi 	 * interrupt to defer the wakeup.
8909d5d5c61Smpi 	 */
8919d5d5c61Smpi 	softintr_schedule(sc->ds_si);
8929d5d5c61Smpi }
8939d5d5c61Smpi 
8949d5d5c61Smpi void
8959d5d5c61Smpi dt_deferred_wakeup(void *arg)
8969d5d5c61Smpi {
8979d5d5c61Smpi 	struct dt_softc *sc = arg;
8989d5d5c61Smpi 
8999d5d5c61Smpi 	wakeup(sc);
9009d5d5c61Smpi }
901