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