xref: /openbsd/sys/dev/dt/dt_dev.c (revision 18b19e82)
1*18b19e82Smpi /*	$OpenBSD: dt_dev.c,v 1.40 2024/11/05 08:11:54 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 */
105f5199088Smpi 	unsigned int		 dc_readevt;	/* [r] # of events read */
106f5199088Smpi };
107f5199088Smpi 
108f5199088Smpi /*
10991b2ecf6Smpi  * Descriptor associated with each program opening /dev/dt.  It is used
11091b2ecf6Smpi  * to keep track of enabled PCBs.
11191b2ecf6Smpi  *
11291b2ecf6Smpi  *  Locks used to protect struct members in this file:
11311c54b09Smvs  *	a	atomic
114b609c616Santon  *	K	kernel lock
115cc4b6028Smpi  *	r	owned by thread doing read(2)
116f5199088Smpi  *	I	invariant after initialization
11791b2ecf6Smpi  */
11891b2ecf6Smpi struct dt_softc {
119b609c616Santon 	SLIST_ENTRY(dt_softc)	 ds_next;	/* [K] descriptor list */
12091b2ecf6Smpi 	int			 ds_unit;	/* [I] D_CLONE unique unit */
12191b2ecf6Smpi 	pid_t			 ds_pid;	/* [I] PID of tracing program */
1229d5d5c61Smpi 	void			*ds_si;		/* [I] to defer wakeup(9) */
12391b2ecf6Smpi 
124b609c616Santon 	struct dt_pcb_list	 ds_pcbs;	/* [K] list of enabled PCBs */
125b609c616Santon 	int			 ds_recording;	/* [K] currently recording? */
126f5199088Smpi 	unsigned int		 ds_evtcnt;	/* [a] # of readable evts */
12791b2ecf6Smpi 
128f5199088Smpi 	struct dt_cpubuf	 ds_cpu[MAXCPUS]; /* [I] Per-cpu event states */
129f5199088Smpi 	unsigned int		 ds_lastcpu;	/* [r] last CPU ring read(2). */
13091b2ecf6Smpi };
13191b2ecf6Smpi 
132b609c616Santon SLIST_HEAD(, dt_softc) dtdev_list;	/* [K] list of open /dev/dt nodes */
13391b2ecf6Smpi 
13491b2ecf6Smpi /*
13591b2ecf6Smpi  * Probes are created during dt_attach() and never modified/freed during
13691b2ecf6Smpi  * the lifetime of the system.  That's why we consider them as [I]mmutable.
13791b2ecf6Smpi  */
13891b2ecf6Smpi unsigned int			dt_nprobes;	/* [I] # of probes available */
13991b2ecf6Smpi SIMPLEQ_HEAD(, dt_probe)	dt_probe_list;	/* [I] list of probes */
14091b2ecf6Smpi 
14191b2ecf6Smpi struct rwlock			dt_lock = RWLOCK_INITIALIZER("dtlk");
142b609c616Santon volatile uint32_t		dt_tracing = 0;	/* [K] # of processes tracing */
14391b2ecf6Smpi 
14411c54b09Smvs int allowdt;					/* [a] */
145a5bcf5abSbluhm 
14691b2ecf6Smpi void	dtattach(struct device *, struct device *, void *);
14791b2ecf6Smpi int	dtopen(dev_t, int, int, struct proc *);
14891b2ecf6Smpi int	dtclose(dev_t, int, int, struct proc *);
14991b2ecf6Smpi int	dtread(dev_t, struct uio *, int);
15091b2ecf6Smpi int	dtioctl(dev_t, u_long, caddr_t, int, struct proc *);
15191b2ecf6Smpi 
15291b2ecf6Smpi struct	dt_softc *dtlookup(int);
153f5199088Smpi struct	dt_softc *dtalloc(void);
154f5199088Smpi void	dtfree(struct dt_softc *);
15591b2ecf6Smpi 
15691b2ecf6Smpi int	dt_ioctl_list_probes(struct dt_softc *, struct dtioc_probe *);
157cd5e5223Sbluhm int	dt_ioctl_get_args(struct dt_softc *, struct dtioc_arg *);
15891b2ecf6Smpi int	dt_ioctl_get_stats(struct dt_softc *, struct dtioc_stat *);
15991b2ecf6Smpi int	dt_ioctl_record_start(struct dt_softc *);
16091b2ecf6Smpi void	dt_ioctl_record_stop(struct dt_softc *);
16191b2ecf6Smpi int	dt_ioctl_probe_enable(struct dt_softc *, struct dtioc_req *);
162840df46fSjasper int	dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *);
163a28bb56fSclaudio int	dt_ioctl_get_auxbase(struct dt_softc *, struct dtioc_getaux *);
16491b2ecf6Smpi 
165f5199088Smpi int	dt_ring_copy(struct dt_cpubuf *, struct uio *, size_t, size_t *);
16691b2ecf6Smpi 
1679d5d5c61Smpi void	dt_wakeup(struct dt_softc *);
1689d5d5c61Smpi void	dt_deferred_wakeup(void *);
1699d5d5c61Smpi 
17091b2ecf6Smpi void
dtattach(struct device * parent,struct device * self,void * aux)17191b2ecf6Smpi dtattach(struct device *parent, struct device *self, void *aux)
17291b2ecf6Smpi {
17391b2ecf6Smpi 	SLIST_INIT(&dtdev_list);
17491b2ecf6Smpi 	SIMPLEQ_INIT(&dt_probe_list);
17591b2ecf6Smpi 
17691b2ecf6Smpi 	/* Init providers */
17791b2ecf6Smpi 	dt_nprobes += dt_prov_profile_init();
17891b2ecf6Smpi 	dt_nprobes += dt_prov_syscall_init();
17991b2ecf6Smpi 	dt_nprobes += dt_prov_static_init();
180840df46fSjasper #ifdef DDBPROF
181840df46fSjasper 	dt_nprobes += dt_prov_kprobe_init();
182840df46fSjasper #endif
18391b2ecf6Smpi }
18491b2ecf6Smpi 
18591b2ecf6Smpi int
dtopen(dev_t dev,int flags,int mode,struct proc * p)18691b2ecf6Smpi dtopen(dev_t dev, int flags, int mode, struct proc *p)
18791b2ecf6Smpi {
18891b2ecf6Smpi 	struct dt_softc *sc;
18991b2ecf6Smpi 	int unit = minor(dev);
190c4318b75Smpi 
19111c54b09Smvs 	if (atomic_load_int(&allowdt) == 0)
192c4318b75Smpi 		return EPERM;
19391b2ecf6Smpi 
194f5199088Smpi 	sc = dtalloc();
19591b2ecf6Smpi 	if (sc == NULL)
19691b2ecf6Smpi 		return ENOMEM;
19791b2ecf6Smpi 
198c57c5c68Sbluhm 	/* no sleep after this point */
199c57c5c68Sbluhm 	if (dtlookup(unit) != NULL) {
200f5199088Smpi 		dtfree(sc);
201c57c5c68Sbluhm 		return EBUSY;
202c57c5c68Sbluhm 	}
20391b2ecf6Smpi 
20491b2ecf6Smpi 	sc->ds_unit = unit;
20591b2ecf6Smpi 	sc->ds_pid = p->p_p->ps_pid;
20691b2ecf6Smpi 	TAILQ_INIT(&sc->ds_pcbs);
207f5199088Smpi 	sc->ds_lastcpu = 0;
20891b2ecf6Smpi 	sc->ds_evtcnt = 0;
20991b2ecf6Smpi 
21091b2ecf6Smpi 	SLIST_INSERT_HEAD(&dtdev_list, sc, ds_next);
21191b2ecf6Smpi 
21291b2ecf6Smpi 	DPRINTF("dt%d: pid %d open\n", sc->ds_unit, sc->ds_pid);
21391b2ecf6Smpi 
21491b2ecf6Smpi 	return 0;
21591b2ecf6Smpi }
21691b2ecf6Smpi 
21791b2ecf6Smpi int
dtclose(dev_t dev,int flags,int mode,struct proc * p)21891b2ecf6Smpi dtclose(dev_t dev, int flags, int mode, struct proc *p)
21991b2ecf6Smpi {
22091b2ecf6Smpi 	struct dt_softc *sc;
22191b2ecf6Smpi 	int unit = minor(dev);
22291b2ecf6Smpi 
22391b2ecf6Smpi 	sc = dtlookup(unit);
22491b2ecf6Smpi 	KASSERT(sc != NULL);
22591b2ecf6Smpi 
22691b2ecf6Smpi 	DPRINTF("dt%d: pid %d close\n", sc->ds_unit, sc->ds_pid);
22791b2ecf6Smpi 
22891b2ecf6Smpi 	SLIST_REMOVE(&dtdev_list, sc, dt_softc, ds_next);
22991b2ecf6Smpi 	dt_ioctl_record_stop(sc);
23091b2ecf6Smpi 	dt_pcb_purge(&sc->ds_pcbs);
231f5199088Smpi 	dtfree(sc);
23291b2ecf6Smpi 
23391b2ecf6Smpi 	return 0;
23491b2ecf6Smpi }
23591b2ecf6Smpi 
23691b2ecf6Smpi int
dtread(dev_t dev,struct uio * uio,int flags)23791b2ecf6Smpi dtread(dev_t dev, struct uio *uio, int flags)
23891b2ecf6Smpi {
23991b2ecf6Smpi 	struct dt_softc *sc;
240f5199088Smpi 	struct dt_cpubuf *dc;
241f5199088Smpi 	int i, error = 0, unit = minor(dev);
2429ff65b2bSmpi 	size_t count, max, read = 0;
24391b2ecf6Smpi 
24491b2ecf6Smpi 	sc = dtlookup(unit);
24591b2ecf6Smpi 	KASSERT(sc != NULL);
24691b2ecf6Smpi 
2479ff65b2bSmpi 	max = howmany(uio->uio_resid, sizeof(struct dt_evt));
2489ff65b2bSmpi 	if (max < 1)
24991b2ecf6Smpi 		return (EMSGSIZE);
25091b2ecf6Smpi 
251f5199088Smpi 	while (!atomic_load_int(&sc->ds_evtcnt)) {
252f2e7dc09Sclaudio 		sleep_setup(sc, PWAIT | PCATCH, "dtread");
253f5199088Smpi 		error = sleep_finish(0, !atomic_load_int(&sc->ds_evtcnt));
25491b2ecf6Smpi 		if (error == EINTR || error == ERESTART)
25591b2ecf6Smpi 			break;
25691b2ecf6Smpi 	}
25791b2ecf6Smpi 	if (error)
25891b2ecf6Smpi 		return error;
25991b2ecf6Smpi 
26091b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
261f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
2629ff65b2bSmpi 		count = 0;
263f5199088Smpi 		dc = &sc->ds_cpu[(sc->ds_lastcpu + i) % ncpusfound];
264f5199088Smpi 		error = dt_ring_copy(dc, uio, max, &count);
265baa78d7bSmpi 		if (error && count == 0)
2669ff65b2bSmpi 			break;
2679ff65b2bSmpi 
26891b2ecf6Smpi 		read += count;
2699ff65b2bSmpi 		max -= count;
2709ff65b2bSmpi 		if (max == 0)
27191b2ecf6Smpi 			break;
27291b2ecf6Smpi 	}
273f5199088Smpi 	sc->ds_lastcpu += i % ncpusfound;
27491b2ecf6Smpi 
275f5199088Smpi 	atomic_sub_int(&sc->ds_evtcnt, read);
27691b2ecf6Smpi 
2779ff65b2bSmpi 	return error;
27891b2ecf6Smpi }
27991b2ecf6Smpi 
28091b2ecf6Smpi int
dtioctl(dev_t dev,u_long cmd,caddr_t addr,int flag,struct proc * p)28191b2ecf6Smpi dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
28291b2ecf6Smpi {
28391b2ecf6Smpi 	struct dt_softc *sc;
28491b2ecf6Smpi 	int unit = minor(dev);
28591b2ecf6Smpi 	int on, error = 0;
28691b2ecf6Smpi 
28791b2ecf6Smpi 	sc = dtlookup(unit);
28891b2ecf6Smpi 	KASSERT(sc != NULL);
28991b2ecf6Smpi 
29091b2ecf6Smpi 	switch (cmd) {
29191b2ecf6Smpi 	case DTIOCGPLIST:
29291b2ecf6Smpi 		return dt_ioctl_list_probes(sc, (struct dtioc_probe *)addr);
293cd5e5223Sbluhm 	case DTIOCGARGS:
294cd5e5223Sbluhm 		return dt_ioctl_get_args(sc, (struct dtioc_arg *)addr);
29591b2ecf6Smpi 	case DTIOCGSTATS:
29691b2ecf6Smpi 		return dt_ioctl_get_stats(sc, (struct dtioc_stat *)addr);
29791b2ecf6Smpi 	case DTIOCRECORD:
29891b2ecf6Smpi 	case DTIOCPRBENABLE:
299840df46fSjasper 	case DTIOCPRBDISABLE:
300a28bb56fSclaudio 	case DTIOCGETAUXBASE:
30191b2ecf6Smpi 		/* root only ioctl(2) */
30291b2ecf6Smpi 		break;
30391b2ecf6Smpi 	default:
30491b2ecf6Smpi 		return ENOTTY;
30591b2ecf6Smpi 	}
30691b2ecf6Smpi 
30791b2ecf6Smpi 	if ((error = suser(p)) != 0)
30891b2ecf6Smpi 		return error;
30991b2ecf6Smpi 
31091b2ecf6Smpi 	switch (cmd) {
31191b2ecf6Smpi 	case DTIOCRECORD:
31291b2ecf6Smpi 		on = *(int *)addr;
31391b2ecf6Smpi 		if (on)
31491b2ecf6Smpi 			error = dt_ioctl_record_start(sc);
31591b2ecf6Smpi 		else
31691b2ecf6Smpi 			dt_ioctl_record_stop(sc);
31791b2ecf6Smpi 		break;
31891b2ecf6Smpi 	case DTIOCPRBENABLE:
31991b2ecf6Smpi 		error = dt_ioctl_probe_enable(sc, (struct dtioc_req *)addr);
32091b2ecf6Smpi 		break;
321840df46fSjasper 	case DTIOCPRBDISABLE:
322840df46fSjasper 		error = dt_ioctl_probe_disable(sc, (struct dtioc_req *)addr);
323840df46fSjasper 		break;
324a28bb56fSclaudio 	case DTIOCGETAUXBASE:
325a28bb56fSclaudio 		error = dt_ioctl_get_auxbase(sc, (struct dtioc_getaux *)addr);
326a28bb56fSclaudio 		break;
32791b2ecf6Smpi 	default:
32891b2ecf6Smpi 		KASSERT(0);
32991b2ecf6Smpi 	}
33091b2ecf6Smpi 
33191b2ecf6Smpi 	return error;
33291b2ecf6Smpi }
33391b2ecf6Smpi 
33491b2ecf6Smpi struct dt_softc *
dtlookup(int unit)33591b2ecf6Smpi dtlookup(int unit)
33691b2ecf6Smpi {
33791b2ecf6Smpi 	struct dt_softc *sc;
33891b2ecf6Smpi 
33991b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
34091b2ecf6Smpi 
34191b2ecf6Smpi 	SLIST_FOREACH(sc, &dtdev_list, ds_next) {
34291b2ecf6Smpi 		if (sc->ds_unit == unit)
34391b2ecf6Smpi 			break;
34491b2ecf6Smpi 	}
34591b2ecf6Smpi 
34691b2ecf6Smpi 	return sc;
34791b2ecf6Smpi }
34891b2ecf6Smpi 
349f5199088Smpi struct dt_softc *
dtalloc(void)350f5199088Smpi dtalloc(void)
351f5199088Smpi {
352f5199088Smpi 	struct dt_softc *sc;
353f5199088Smpi 	struct dt_evt *dtev;
354f5199088Smpi 	int i;
355f5199088Smpi 
356f5199088Smpi 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
357f5199088Smpi 	if (sc == NULL)
358f5199088Smpi 		return NULL;
359f5199088Smpi 
360f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
361*18b19e82Smpi 		dtev = mallocarray(DT_EVTRING_SIZE, sizeof(*dtev), M_DEVBUF,
362f5199088Smpi 		    M_WAITOK|M_CANFAIL|M_ZERO);
363f5199088Smpi 		if (dtev == NULL)
364f5199088Smpi 			break;
365f5199088Smpi 		sc->ds_cpu[i].dc_ring = dtev;
366f5199088Smpi 	}
367f5199088Smpi 	if (i < ncpusfound) {
368f5199088Smpi 		dtfree(sc);
369f5199088Smpi 		return NULL;
370f5199088Smpi 	}
371f5199088Smpi 
372*18b19e82Smpi 	sc->ds_si = softintr_establish(IPL_SOFTCLOCK, dt_deferred_wakeup, sc);
373*18b19e82Smpi 	if (sc->ds_si == NULL) {
374*18b19e82Smpi 		dtfree(sc);
375*18b19e82Smpi 		return NULL;
376*18b19e82Smpi 	}
377*18b19e82Smpi 
378f5199088Smpi 	return sc;
379f5199088Smpi }
380f5199088Smpi 
381f5199088Smpi void
dtfree(struct dt_softc * sc)382f5199088Smpi dtfree(struct dt_softc *sc)
383f5199088Smpi {
384f5199088Smpi 	struct dt_evt *dtev;
385f5199088Smpi 	int i;
386f5199088Smpi 
387*18b19e82Smpi 	if (sc->ds_si != NULL)
388*18b19e82Smpi 		softintr_disestablish(sc->ds_si);
389*18b19e82Smpi 
390f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
391f5199088Smpi 		dtev = sc->ds_cpu[i].dc_ring;
392*18b19e82Smpi 		free(dtev, M_DEVBUF, DT_EVTRING_SIZE * sizeof(*dtev));
393f5199088Smpi 	}
394f5199088Smpi 	free(sc, M_DEVBUF, sizeof(*sc));
395f5199088Smpi }
396f5199088Smpi 
39791b2ecf6Smpi int
dt_ioctl_list_probes(struct dt_softc * sc,struct dtioc_probe * dtpr)39891b2ecf6Smpi dt_ioctl_list_probes(struct dt_softc *sc, struct dtioc_probe *dtpr)
39991b2ecf6Smpi {
40091b2ecf6Smpi 	struct dtioc_probe_info info, *dtpi;
40191b2ecf6Smpi 	struct dt_probe *dtp;
40291b2ecf6Smpi 	size_t size;
40391b2ecf6Smpi 	int error = 0;
40491b2ecf6Smpi 
40591b2ecf6Smpi 	size = dtpr->dtpr_size;
406915014bfSmpi 	dtpr->dtpr_size = dt_nprobes * sizeof(*dtpi);
407915014bfSmpi 	if (size == 0)
408915014bfSmpi 		return 0;
409915014bfSmpi 
41091b2ecf6Smpi 	dtpi = dtpr->dtpr_probes;
41191b2ecf6Smpi 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
41291b2ecf6Smpi 		if (size < sizeof(*dtpi)) {
41391b2ecf6Smpi 			error = ENOSPC;
41491b2ecf6Smpi 			break;
41591b2ecf6Smpi 		}
416cd5e5223Sbluhm 		memset(&info, 0, sizeof(info));
41791b2ecf6Smpi 		info.dtpi_pbn = dtp->dtp_pbn;
41823829576Smpi 		info.dtpi_nargs = dtp->dtp_nargs;
41991b2ecf6Smpi 		strlcpy(info.dtpi_prov, dtp->dtp_prov->dtpv_name,
42091b2ecf6Smpi 		    sizeof(info.dtpi_prov));
42191b2ecf6Smpi 		strlcpy(info.dtpi_func, dtp->dtp_func, sizeof(info.dtpi_func));
42291b2ecf6Smpi 		strlcpy(info.dtpi_name, dtp->dtp_name, sizeof(info.dtpi_name));
42391b2ecf6Smpi 		error = copyout(&info, dtpi, sizeof(*dtpi));
42491b2ecf6Smpi 		if (error)
42591b2ecf6Smpi 			break;
42691b2ecf6Smpi 		size -= sizeof(*dtpi);
42791b2ecf6Smpi 		dtpi++;
428cd5e5223Sbluhm 	}
429cd5e5223Sbluhm 
430cd5e5223Sbluhm 	return error;
431cd5e5223Sbluhm }
432cd5e5223Sbluhm 
433cd5e5223Sbluhm int
dt_ioctl_get_args(struct dt_softc * sc,struct dtioc_arg * dtar)434cd5e5223Sbluhm dt_ioctl_get_args(struct dt_softc *sc, struct dtioc_arg *dtar)
435cd5e5223Sbluhm {
436cd5e5223Sbluhm 	struct dtioc_arg_info info, *dtai;
437cd5e5223Sbluhm 	struct dt_probe *dtp;
438cd5e5223Sbluhm 	size_t size, n, t;
439cd5e5223Sbluhm 	uint32_t pbn;
440cd5e5223Sbluhm 	int error = 0;
441cd5e5223Sbluhm 
442cd5e5223Sbluhm 	pbn = dtar->dtar_pbn;
443cd5e5223Sbluhm 	if (pbn == 0 || pbn > dt_nprobes)
444cd5e5223Sbluhm 		return EINVAL;
445cd5e5223Sbluhm 
446cd5e5223Sbluhm 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
447cd5e5223Sbluhm 		if (pbn == dtp->dtp_pbn)
448cd5e5223Sbluhm 			break;
449cd5e5223Sbluhm 	}
450cd5e5223Sbluhm 	if (dtp == NULL)
451cd5e5223Sbluhm 		return EINVAL;
452cd5e5223Sbluhm 
453cd5e5223Sbluhm 	if (dtp->dtp_sysnum != 0) {
454cd5e5223Sbluhm 		/* currently not supported for system calls */
455cd5e5223Sbluhm 		dtar->dtar_size = 0;
456cd5e5223Sbluhm 		return 0;
457cd5e5223Sbluhm 	}
458cd5e5223Sbluhm 
459cd5e5223Sbluhm 	size = dtar->dtar_size;
460cd5e5223Sbluhm 	dtar->dtar_size = dtp->dtp_nargs * sizeof(*dtar);
461cd5e5223Sbluhm 	if (size == 0)
462cd5e5223Sbluhm 		return 0;
463cd5e5223Sbluhm 
464cd5e5223Sbluhm 	t = 0;
465cd5e5223Sbluhm 	dtai = dtar->dtar_args;
466cd5e5223Sbluhm 	for (n = 0; n < dtp->dtp_nargs; n++) {
467cd5e5223Sbluhm 		if (size < sizeof(*dtai)) {
468cd5e5223Sbluhm 			error = ENOSPC;
469cd5e5223Sbluhm 			break;
470cd5e5223Sbluhm 		}
471cd5e5223Sbluhm 		if (n >= DTMAXARGTYPES || dtp->dtp_argtype[n] == NULL)
472cd5e5223Sbluhm 			continue;
473cd5e5223Sbluhm 		memset(&info, 0, sizeof(info));
474cd5e5223Sbluhm 		info.dtai_pbn = dtp->dtp_pbn;
475cd5e5223Sbluhm 		info.dtai_argn = t++;
476cd5e5223Sbluhm 		strlcpy(info.dtai_argtype, dtp->dtp_argtype[n],
477cd5e5223Sbluhm 		    sizeof(info.dtai_argtype));
478cd5e5223Sbluhm 		error = copyout(&info, dtai, sizeof(*dtai));
479cd5e5223Sbluhm 		if (error)
480cd5e5223Sbluhm 			break;
481cd5e5223Sbluhm 		size -= sizeof(*dtai);
482cd5e5223Sbluhm 		dtai++;
483cd5e5223Sbluhm 	}
484cd5e5223Sbluhm 	dtar->dtar_size = t * sizeof(*dtar);
48591b2ecf6Smpi 
48691b2ecf6Smpi 	return error;
48791b2ecf6Smpi }
48891b2ecf6Smpi 
48991b2ecf6Smpi int
dt_ioctl_get_stats(struct dt_softc * sc,struct dtioc_stat * dtst)49091b2ecf6Smpi dt_ioctl_get_stats(struct dt_softc *sc, struct dtioc_stat *dtst)
49191b2ecf6Smpi {
492f5199088Smpi 	struct dt_cpubuf *dc;
493f5199088Smpi 	uint64_t readevt = 0, dropevt = 0;
494f5199088Smpi 	int i;
49591b2ecf6Smpi 
496f5199088Smpi 	for (i = 0; i < ncpusfound; i++) {
497f5199088Smpi 		dc = &sc->ds_cpu[i];
498f5199088Smpi 
499f5199088Smpi 		membar_consumer();
500f5199088Smpi 		dropevt += dc->dc_dropevt;
501f5199088Smpi 		readevt += dc->dc_readevt;
502f5199088Smpi 	}
503f5199088Smpi 
504f5199088Smpi 	dtst->dtst_readevt = readevt;
505f5199088Smpi 	dtst->dtst_dropevt = dropevt;
50691b2ecf6Smpi 	return 0;
50791b2ecf6Smpi }
50891b2ecf6Smpi 
50991b2ecf6Smpi int
dt_ioctl_record_start(struct dt_softc * sc)51091b2ecf6Smpi dt_ioctl_record_start(struct dt_softc *sc)
51191b2ecf6Smpi {
512a79ed6b1Scheloha 	uint64_t now;
51391b2ecf6Smpi 	struct dt_pcb *dp;
51491b2ecf6Smpi 
51591b2ecf6Smpi 	if (sc->ds_recording)
51691b2ecf6Smpi 		return EBUSY;
51791b2ecf6Smpi 
51891b2ecf6Smpi 	KERNEL_ASSERT_LOCKED();
51991b2ecf6Smpi 	if (TAILQ_EMPTY(&sc->ds_pcbs))
52091b2ecf6Smpi 		return ENOENT;
52191b2ecf6Smpi 
5220e146e1bSvisa 	rw_enter_write(&dt_lock);
523a79ed6b1Scheloha 	now = nsecuptime();
52491b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
52591b2ecf6Smpi 		struct dt_probe *dtp = dp->dp_dtp;
52691b2ecf6Smpi 
52791b2ecf6Smpi 		SMR_SLIST_INSERT_HEAD_LOCKED(&dtp->dtp_pcbs, dp, dp_pnext);
52891b2ecf6Smpi 		dtp->dtp_recording++;
52991b2ecf6Smpi 		dtp->dtp_prov->dtpv_recording++;
530c56c27b6Scheloha 
531c56c27b6Scheloha 		if (dp->dp_nsecs != 0) {
532c56c27b6Scheloha 			clockintr_bind(&dp->dp_clockintr, dp->dp_cpu, dt_clock,
533c56c27b6Scheloha 			    dp);
534a79ed6b1Scheloha 			clockintr_schedule(&dp->dp_clockintr,
535a79ed6b1Scheloha 			    now + dp->dp_nsecs);
536c56c27b6Scheloha 		}
53791b2ecf6Smpi 	}
5380e146e1bSvisa 	rw_exit_write(&dt_lock);
53991b2ecf6Smpi 
54091b2ecf6Smpi 	sc->ds_recording = 1;
54191b2ecf6Smpi 	dt_tracing++;
54291b2ecf6Smpi 
54391b2ecf6Smpi 	return 0;
54491b2ecf6Smpi }
54591b2ecf6Smpi 
54691b2ecf6Smpi void
dt_ioctl_record_stop(struct dt_softc * sc)54791b2ecf6Smpi dt_ioctl_record_stop(struct dt_softc *sc)
54891b2ecf6Smpi {
54991b2ecf6Smpi 	struct dt_pcb *dp;
55091b2ecf6Smpi 
55191b2ecf6Smpi 	if (!sc->ds_recording)
55291b2ecf6Smpi 		return;
55391b2ecf6Smpi 
55491b2ecf6Smpi 	DPRINTF("dt%d: pid %d disable\n", sc->ds_unit, sc->ds_pid);
55591b2ecf6Smpi 
55691b2ecf6Smpi 	dt_tracing--;
55791b2ecf6Smpi 	sc->ds_recording = 0;
55891b2ecf6Smpi 
5590e146e1bSvisa 	rw_enter_write(&dt_lock);
56091b2ecf6Smpi 	TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) {
56191b2ecf6Smpi 		struct dt_probe *dtp = dp->dp_dtp;
56291b2ecf6Smpi 
563c56c27b6Scheloha 		/*
564c56c27b6Scheloha 		 * Set an execution barrier to ensure the shared
565c56c27b6Scheloha 		 * reference to dp is inactive.
566c56c27b6Scheloha 		 */
567c56c27b6Scheloha 		if (dp->dp_nsecs != 0)
568c56c27b6Scheloha 			clockintr_unbind(&dp->dp_clockintr, CL_BARRIER);
569c56c27b6Scheloha 
57091b2ecf6Smpi 		dtp->dtp_recording--;
57191b2ecf6Smpi 		dtp->dtp_prov->dtpv_recording--;
57291b2ecf6Smpi 		SMR_SLIST_REMOVE_LOCKED(&dtp->dtp_pcbs, dp, dt_pcb, dp_pnext);
57391b2ecf6Smpi 	}
5740e146e1bSvisa 	rw_exit_write(&dt_lock);
5750e146e1bSvisa 
5760e146e1bSvisa 	/* Wait until readers cannot access the PCBs. */
5770e146e1bSvisa 	smr_barrier();
57891b2ecf6Smpi }
57991b2ecf6Smpi 
58091b2ecf6Smpi int
dt_ioctl_probe_enable(struct dt_softc * sc,struct dtioc_req * dtrq)58191b2ecf6Smpi dt_ioctl_probe_enable(struct dt_softc *sc, struct dtioc_req *dtrq)
58291b2ecf6Smpi {
58391b2ecf6Smpi 	struct dt_pcb_list plist;
58491b2ecf6Smpi 	struct dt_probe *dtp;
58591b2ecf6Smpi 	int error;
58691b2ecf6Smpi 
58791b2ecf6Smpi 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
58891b2ecf6Smpi 		if (dtp->dtp_pbn == dtrq->dtrq_pbn)
58991b2ecf6Smpi 			break;
59091b2ecf6Smpi 	}
59191b2ecf6Smpi 	if (dtp == NULL)
59291b2ecf6Smpi 		return ENOENT;
59391b2ecf6Smpi 
59491b2ecf6Smpi 	TAILQ_INIT(&plist);
59591b2ecf6Smpi 	error = dtp->dtp_prov->dtpv_alloc(dtp, sc, &plist, dtrq);
59691b2ecf6Smpi 	if (error)
59791b2ecf6Smpi 		return error;
59891b2ecf6Smpi 
59991b2ecf6Smpi 	DPRINTF("dt%d: pid %d enable %u : %b\n", sc->ds_unit, sc->ds_pid,
60091b2ecf6Smpi 	    dtrq->dtrq_pbn, (unsigned int)dtrq->dtrq_evtflags, DTEVT_FLAG_BITS);
60191b2ecf6Smpi 
60291b2ecf6Smpi 	/* Append all PCBs to this instance */
6031e9785c2Sbket 	TAILQ_CONCAT(&sc->ds_pcbs, &plist, dp_snext);
60491b2ecf6Smpi 
60591b2ecf6Smpi 	return 0;
60691b2ecf6Smpi }
60791b2ecf6Smpi 
608840df46fSjasper int
dt_ioctl_probe_disable(struct dt_softc * sc,struct dtioc_req * dtrq)609840df46fSjasper dt_ioctl_probe_disable(struct dt_softc *sc, struct dtioc_req *dtrq)
610840df46fSjasper {
611840df46fSjasper 	struct dt_probe *dtp;
612840df46fSjasper 	int error;
613840df46fSjasper 
614840df46fSjasper 	SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
615840df46fSjasper 		if (dtp->dtp_pbn == dtrq->dtrq_pbn)
616840df46fSjasper 			break;
617840df46fSjasper 	}
618840df46fSjasper 	if (dtp == NULL)
619840df46fSjasper 		return ENOENT;
620840df46fSjasper 
621840df46fSjasper 	if (dtp->dtp_prov->dtpv_dealloc) {
622840df46fSjasper 		error = dtp->dtp_prov->dtpv_dealloc(dtp, sc, dtrq);
623840df46fSjasper 		if (error)
624840df46fSjasper 			return error;
625840df46fSjasper 	}
626840df46fSjasper 
627840df46fSjasper 	DPRINTF("dt%d: pid %d dealloc\n", sc->ds_unit, sc->ds_pid,
628840df46fSjasper 	    dtrq->dtrq_pbn);
629840df46fSjasper 
630840df46fSjasper 	return 0;
631840df46fSjasper }
632840df46fSjasper 
633a28bb56fSclaudio int
dt_ioctl_get_auxbase(struct dt_softc * sc,struct dtioc_getaux * dtga)634a28bb56fSclaudio dt_ioctl_get_auxbase(struct dt_softc *sc, struct dtioc_getaux *dtga)
635a28bb56fSclaudio {
636a28bb56fSclaudio 	struct uio uio;
637a28bb56fSclaudio 	struct iovec iov;
638a28bb56fSclaudio 	struct process *pr;
639a28bb56fSclaudio 	struct proc *p = curproc;
640a28bb56fSclaudio 	AuxInfo auxv[ELF_AUX_ENTRIES];
641a28bb56fSclaudio 	int i, error;
642a28bb56fSclaudio 
643a28bb56fSclaudio 	dtga->dtga_auxbase = 0;
644a28bb56fSclaudio 
645a28bb56fSclaudio 	if ((pr = prfind(dtga->dtga_pid)) == NULL)
646a28bb56fSclaudio 		return ESRCH;
647a28bb56fSclaudio 
648a28bb56fSclaudio 	iov.iov_base = auxv;
649a28bb56fSclaudio 	iov.iov_len = sizeof(auxv);
650a28bb56fSclaudio 	uio.uio_iov = &iov;
651a28bb56fSclaudio 	uio.uio_iovcnt = 1;
652a28bb56fSclaudio 	uio.uio_offset = pr->ps_auxinfo;
653a28bb56fSclaudio 	uio.uio_resid = sizeof(auxv);
654a28bb56fSclaudio 	uio.uio_segflg = UIO_SYSSPACE;
655a28bb56fSclaudio 	uio.uio_procp = p;
656a28bb56fSclaudio 	uio.uio_rw = UIO_READ;
657a28bb56fSclaudio 
658a28bb56fSclaudio 	error = process_domem(p, pr, &uio, PT_READ_D);
659a28bb56fSclaudio 	if (error)
660a28bb56fSclaudio 		return error;
661a28bb56fSclaudio 
662a28bb56fSclaudio 	for (i = 0; i < ELF_AUX_ENTRIES; i++)
663a28bb56fSclaudio 		if (auxv[i].au_id == AUX_base)
664a28bb56fSclaudio 			dtga->dtga_auxbase = auxv[i].au_v;
665a28bb56fSclaudio 
666a28bb56fSclaudio 	return 0;
667a28bb56fSclaudio }
668a28bb56fSclaudio 
66991b2ecf6Smpi struct dt_probe *
dt_dev_alloc_probe(const char * func,const char * name,struct dt_provider * dtpv)67091b2ecf6Smpi dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv)
67191b2ecf6Smpi {
67291b2ecf6Smpi 	struct dt_probe *dtp;
67391b2ecf6Smpi 
67491b2ecf6Smpi 	dtp = malloc(sizeof(*dtp), M_DT, M_NOWAIT|M_ZERO);
67591b2ecf6Smpi 	if (dtp == NULL)
67691b2ecf6Smpi 		return NULL;
67791b2ecf6Smpi 
67891b2ecf6Smpi 	SMR_SLIST_INIT(&dtp->dtp_pcbs);
67991b2ecf6Smpi 	dtp->dtp_prov = dtpv;
68091b2ecf6Smpi 	dtp->dtp_func = func;
68191b2ecf6Smpi 	dtp->dtp_name = name;
68291b2ecf6Smpi 	dtp->dtp_sysnum = -1;
683840df46fSjasper 	dtp->dtp_ref = 0;
684840df46fSjasper 
68591b2ecf6Smpi 	return dtp;
68691b2ecf6Smpi }
68791b2ecf6Smpi 
68891b2ecf6Smpi void
dt_dev_register_probe(struct dt_probe * dtp)68991b2ecf6Smpi dt_dev_register_probe(struct dt_probe *dtp)
69091b2ecf6Smpi {
69191b2ecf6Smpi 	static uint64_t probe_nb;
69291b2ecf6Smpi 
69391b2ecf6Smpi 	dtp->dtp_pbn = ++probe_nb;
69491b2ecf6Smpi 	SIMPLEQ_INSERT_TAIL(&dt_probe_list, dtp, dtp_next);
69591b2ecf6Smpi }
69691b2ecf6Smpi 
69791b2ecf6Smpi struct dt_pcb *
dt_pcb_alloc(struct dt_probe * dtp,struct dt_softc * sc)69891b2ecf6Smpi dt_pcb_alloc(struct dt_probe *dtp, struct dt_softc *sc)
69991b2ecf6Smpi {
70091b2ecf6Smpi 	struct dt_pcb *dp;
70191b2ecf6Smpi 
70291b2ecf6Smpi 	dp = malloc(sizeof(*dp), M_DT, M_WAITOK|M_CANFAIL|M_ZERO);
70391b2ecf6Smpi 	if (dp == NULL)
704f5199088Smpi 		return NULL;
70591b2ecf6Smpi 
70691b2ecf6Smpi 	dp->dp_sc = sc;
70791b2ecf6Smpi 	dp->dp_dtp = dtp;
70891b2ecf6Smpi 	return dp;
70991b2ecf6Smpi }
71091b2ecf6Smpi 
71191b2ecf6Smpi void
dt_pcb_free(struct dt_pcb * dp)71291b2ecf6Smpi dt_pcb_free(struct dt_pcb *dp)
71391b2ecf6Smpi {
71491b2ecf6Smpi 	free(dp, M_DT, sizeof(*dp));
71591b2ecf6Smpi }
71691b2ecf6Smpi 
71791b2ecf6Smpi void
dt_pcb_purge(struct dt_pcb_list * plist)71891b2ecf6Smpi dt_pcb_purge(struct dt_pcb_list *plist)
71991b2ecf6Smpi {
72091b2ecf6Smpi 	struct dt_pcb *dp;
72191b2ecf6Smpi 
72291b2ecf6Smpi 	while ((dp = TAILQ_FIRST(plist)) != NULL) {
72391b2ecf6Smpi 		TAILQ_REMOVE(plist, dp, dp_snext);
72491b2ecf6Smpi 		dt_pcb_free(dp);
72591b2ecf6Smpi 	}
72691b2ecf6Smpi }
72791b2ecf6Smpi 
72891b2ecf6Smpi /*
72991b2ecf6Smpi  * Get a reference to the next free event state from the ring.
73091b2ecf6Smpi  */
73191b2ecf6Smpi struct dt_evt *
dt_pcb_ring_get(struct dt_pcb * dp,int profiling)732ecfa01e0Smpi dt_pcb_ring_get(struct dt_pcb *dp, int profiling)
73391b2ecf6Smpi {
73491b2ecf6Smpi 	struct proc *p = curproc;
73591b2ecf6Smpi 	struct dt_evt *dtev;
736f5199088Smpi 	int prod, cons, distance;
737f5199088Smpi 	struct dt_cpubuf *dc = &dp->dp_sc->ds_cpu[cpu_number()];
73891b2ecf6Smpi 
739f5199088Smpi 	if (dc->dc_inevt == 1)
740f5199088Smpi 		return NULL;
741f5199088Smpi 
742f5199088Smpi 	dc->dc_inevt = 1;
743f5199088Smpi 
744f5199088Smpi 	membar_consumer();
745f5199088Smpi 	prod = dc->dc_prod;
746f5199088Smpi 	cons = dc->dc_cons;
747f5199088Smpi 	distance = prod - cons;
74891b2ecf6Smpi 	if (distance == 1 || distance == (1 - DT_EVTRING_SIZE)) {
74991b2ecf6Smpi 		/* read(2) isn't finished */
750f5199088Smpi 		dc->dc_dropevt++;
751f5199088Smpi 		membar_producer();
752f5199088Smpi 
753f5199088Smpi 		dc->dc_inevt = 0;
75491b2ecf6Smpi 		return NULL;
75591b2ecf6Smpi 	}
75691b2ecf6Smpi 
75791b2ecf6Smpi 	/*
75891b2ecf6Smpi 	 * Save states in next free event slot.
75991b2ecf6Smpi 	 */
760f5199088Smpi 	dtev = &dc->dc_ring[cons];
76191b2ecf6Smpi 	memset(dtev, 0, sizeof(*dtev));
76291b2ecf6Smpi 
76391b2ecf6Smpi 	dtev->dtev_pbn = dp->dp_dtp->dtp_pbn;
76491b2ecf6Smpi 	dtev->dtev_cpu = cpu_number();
76591b2ecf6Smpi 	dtev->dtev_pid = p->p_p->ps_pid;
76621e92265Sbluhm 	dtev->dtev_tid = p->p_tid + THREAD_PID_OFFSET;
76791b2ecf6Smpi 	nanotime(&dtev->dtev_tsp);
76891b2ecf6Smpi 
76991b2ecf6Smpi 	if (ISSET(dp->dp_evtflags, DTEVT_EXECNAME))
77014cb6e73Sderaadt 		strlcpy(dtev->dtev_comm, p->p_p->ps_comm, sizeof(dtev->dtev_comm));
77191b2ecf6Smpi 
772a28bb56fSclaudio 	if (ISSET(dp->dp_evtflags, DTEVT_KSTACK)) {
773ecfa01e0Smpi 		if (profiling)
774ecfa01e0Smpi 			stacktrace_save_at(&dtev->dtev_kstack, DT_FA_PROFILE);
775ecfa01e0Smpi 		else
776ecfa01e0Smpi 			stacktrace_save_at(&dtev->dtev_kstack, DT_FA_STATIC);
77791b2ecf6Smpi 	}
778a28bb56fSclaudio 	if (ISSET(dp->dp_evtflags, DTEVT_USTACK))
779a28bb56fSclaudio 		stacktrace_save_utrace(&dtev->dtev_ustack);
78091b2ecf6Smpi 
78191b2ecf6Smpi 	return dtev;
78291b2ecf6Smpi }
78391b2ecf6Smpi 
78491b2ecf6Smpi void
dt_pcb_ring_consume(struct dt_pcb * dp,struct dt_evt * dtev)78591b2ecf6Smpi dt_pcb_ring_consume(struct dt_pcb *dp, struct dt_evt *dtev)
78691b2ecf6Smpi {
787f5199088Smpi 	struct dt_cpubuf *dc = &dp->dp_sc->ds_cpu[cpu_number()];
78891b2ecf6Smpi 
789f5199088Smpi 	KASSERT(dtev == &dc->dc_ring[dc->dc_cons]);
79091b2ecf6Smpi 
791f5199088Smpi 	dc->dc_cons = (dc->dc_cons + 1) % DT_EVTRING_SIZE;
792f5199088Smpi 	membar_producer();
793f5199088Smpi 
794f5199088Smpi 	atomic_inc_int(&dp->dp_sc->ds_evtcnt);
795f5199088Smpi 	dc->dc_inevt = 0;
796f5199088Smpi 
7979d5d5c61Smpi 	dt_wakeup(dp->dp_sc);
79891b2ecf6Smpi }
79991b2ecf6Smpi 
80091b2ecf6Smpi /*
801f5199088Smpi  * Copy at most `max' events from `dc', producing the same amount
80291b2ecf6Smpi  * of free slots.
80391b2ecf6Smpi  */
80491b2ecf6Smpi int
dt_ring_copy(struct dt_cpubuf * dc,struct uio * uio,size_t max,size_t * rcvd)805f5199088Smpi dt_ring_copy(struct dt_cpubuf *dc, struct uio *uio, size_t max, size_t *rcvd)
80691b2ecf6Smpi {
80791b2ecf6Smpi 	size_t count, copied = 0;
80891b2ecf6Smpi 	unsigned int cons, prod;
8099ff65b2bSmpi 	int error = 0;
81091b2ecf6Smpi 
8119ff65b2bSmpi 	KASSERT(max > 0);
81291b2ecf6Smpi 
813f5199088Smpi 	membar_consumer();
814f5199088Smpi 	cons = dc->dc_cons;
815f5199088Smpi 	prod = dc->dc_prod;
81691b2ecf6Smpi 
81791b2ecf6Smpi 	if (cons < prod)
81891b2ecf6Smpi 		count = DT_EVTRING_SIZE - prod;
81991b2ecf6Smpi 	else
82091b2ecf6Smpi 		count = cons - prod;
82191b2ecf6Smpi 
82291b2ecf6Smpi 	if (count == 0)
8239ff65b2bSmpi 		return 0;
82491b2ecf6Smpi 
8259ff65b2bSmpi 	count = MIN(count, max);
826f5199088Smpi 	error = uiomove(&dc->dc_ring[prod], count * sizeof(struct dt_evt), uio);
8279ff65b2bSmpi 	if (error)
8289ff65b2bSmpi 		return error;
82991b2ecf6Smpi 	copied += count;
83091b2ecf6Smpi 
83191b2ecf6Smpi 	/* Produce */
83291b2ecf6Smpi 	prod = (prod + count) % DT_EVTRING_SIZE;
83391b2ecf6Smpi 
8349ff65b2bSmpi 	/* If the ring didn't wrap, stop here. */
8359ff65b2bSmpi 	if (max == copied || prod != 0 || cons == 0)
83691b2ecf6Smpi 		goto out;
83791b2ecf6Smpi 
8389ff65b2bSmpi 	count = MIN(cons, (max - copied));
839f5199088Smpi 	error = uiomove(&dc->dc_ring[0], count * sizeof(struct dt_evt), uio);
8409ff65b2bSmpi 	if (error)
8419ff65b2bSmpi 		goto out;
8429ff65b2bSmpi 
84391b2ecf6Smpi 	copied += count;
84491b2ecf6Smpi 	prod += count;
84591b2ecf6Smpi 
84691b2ecf6Smpi out:
847f5199088Smpi 	dc->dc_readevt += copied;
848f5199088Smpi 	dc->dc_prod = prod;
849f5199088Smpi 	membar_producer();
8509ff65b2bSmpi 
8519ff65b2bSmpi 	*rcvd = copied;
8529ff65b2bSmpi 	return error;
85391b2ecf6Smpi }
8549d5d5c61Smpi 
8559d5d5c61Smpi void
dt_wakeup(struct dt_softc * sc)8569d5d5c61Smpi dt_wakeup(struct dt_softc *sc)
8579d5d5c61Smpi {
8589d5d5c61Smpi 	/*
8599d5d5c61Smpi 	 * It is not always safe or possible to call wakeup(9) and grab
8609d5d5c61Smpi 	 * the SCHED_LOCK() from a given tracepoint.  This is true for
8619d5d5c61Smpi 	 * any tracepoint that might trigger inside the scheduler or at
8629d5d5c61Smpi 	 * any IPL higher than IPL_SCHED.  For this reason use a soft-
8639d5d5c61Smpi 	 * interrupt to defer the wakeup.
8649d5d5c61Smpi 	 */
8659d5d5c61Smpi 	softintr_schedule(sc->ds_si);
8669d5d5c61Smpi }
8679d5d5c61Smpi 
8689d5d5c61Smpi void
dt_deferred_wakeup(void * arg)8699d5d5c61Smpi dt_deferred_wakeup(void *arg)
8709d5d5c61Smpi {
8719d5d5c61Smpi 	struct dt_softc *sc = arg;
8729d5d5c61Smpi 
8739d5d5c61Smpi 	wakeup(sc);
8749d5d5c61Smpi }
875