xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision 976aa07a885b53e1bc2711082d2f6f113dbdd0bc)
13f6cab07SMatt Macy /*-
23f6cab07SMatt Macy  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33f6cab07SMatt Macy  *
43f6cab07SMatt Macy  * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
53f6cab07SMatt Macy  *
63f6cab07SMatt Macy  * Redistribution and use in source and binary forms, with or without
73f6cab07SMatt Macy  * modification, are permitted provided that the following conditions
83f6cab07SMatt Macy  * are met:
93f6cab07SMatt Macy  * 1. Redistributions of source code must retain the above copyright
103f6cab07SMatt Macy  *    notice, this list of conditions and the following disclaimer.
113f6cab07SMatt Macy  * 2. Redistributions in binary form must reproduce the above copyright
123f6cab07SMatt Macy  *    notice, this list of conditions and the following disclaimer in the
133f6cab07SMatt Macy  *    documentation and/or other materials provided with the distribution.
143f6cab07SMatt Macy  *
153f6cab07SMatt Macy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163f6cab07SMatt Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173f6cab07SMatt Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183f6cab07SMatt Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193f6cab07SMatt Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203f6cab07SMatt Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213f6cab07SMatt Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223f6cab07SMatt Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233f6cab07SMatt Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243f6cab07SMatt Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253f6cab07SMatt Macy  * SUCH DAMAGE.
263f6cab07SMatt Macy  *
273f6cab07SMatt Macy  */
283f6cab07SMatt Macy 
293f6cab07SMatt Macy #include <sys/cdefs.h>
303f6cab07SMatt Macy __FBSDID("$FreeBSD$");
313f6cab07SMatt Macy 
323f6cab07SMatt Macy #include <sys/param.h>
333f6cab07SMatt Macy #include <sys/systm.h>
343f6cab07SMatt Macy #include <sys/queue.h>
353f6cab07SMatt Macy #include <sys/blist.h>
363f6cab07SMatt Macy #include <sys/conf.h>
373f6cab07SMatt Macy #include <sys/exec.h>
383f6cab07SMatt Macy #include <sys/filedesc.h>
393f6cab07SMatt Macy #include <sys/kernel.h>
403f6cab07SMatt Macy #include <sys/linker.h>
413f6cab07SMatt Macy #include <sys/malloc.h>
423f6cab07SMatt Macy #include <sys/mount.h>
433f6cab07SMatt Macy #include <sys/mutex.h>
443f6cab07SMatt Macy #include <sys/proc.h>
453f6cab07SMatt Macy #include <sys/resourcevar.h>
463f6cab07SMatt Macy #include <sys/sbuf.h>
473f6cab07SMatt Macy #include <sys/smp.h>
483f6cab07SMatt Macy #include <sys/socket.h>
493f6cab07SMatt Macy #include <sys/vnode.h>
503f6cab07SMatt Macy #include <sys/bus.h>
513f6cab07SMatt Macy #include <sys/pciio.h>
523f6cab07SMatt Macy 
533f6cab07SMatt Macy #include <dev/pci/pcivar.h>
543f6cab07SMatt Macy #include <dev/pci/pcireg.h>
553f6cab07SMatt Macy 
563f6cab07SMatt Macy #include <net/if.h>
573f6cab07SMatt Macy 
583f6cab07SMatt Macy #include <vm/vm.h>
593f6cab07SMatt Macy #include <vm/pmap.h>
603f6cab07SMatt Macy #include <vm/vm_map.h>
613f6cab07SMatt Macy #include <vm/vm_param.h>
623f6cab07SMatt Macy #include <vm/vm_object.h>
633f6cab07SMatt Macy #include <vm/swap_pager.h>
643f6cab07SMatt Macy 
653f6cab07SMatt Macy #include <machine/bus.h>
663f6cab07SMatt Macy 
673f6cab07SMatt Macy #include <compat/linux/linux_ioctl.h>
683f6cab07SMatt Macy #include <compat/linux/linux_mib.h>
693f6cab07SMatt Macy #include <compat/linux/linux_util.h>
703f6cab07SMatt Macy #include <fs/pseudofs/pseudofs.h>
713f6cab07SMatt Macy 
72f2044a30SJean-Sébastien Pédron #include <asm/atomic.h>
733f6cab07SMatt Macy #include <linux/compat.h>
74f697b943SJake Freeland #include <linux/debugfs.h>
75f697b943SJake Freeland #include <linux/fs.h>
763f6cab07SMatt Macy 
773f6cab07SMatt Macy MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
783f6cab07SMatt Macy 
793f6cab07SMatt Macy static struct pfs_node *debugfs_root;
803f6cab07SMatt Macy 
813f6cab07SMatt Macy #define DM_SYMLINK 0x1
823f6cab07SMatt Macy #define DM_DIR 0x2
833f6cab07SMatt Macy #define DM_FILE 0x3
843f6cab07SMatt Macy 
853f6cab07SMatt Macy struct dentry_meta {
863f6cab07SMatt Macy 	struct dentry dm_dnode;
873f6cab07SMatt Macy 	const struct file_operations *dm_fops;
883f6cab07SMatt Macy 	void *dm_data;
893f6cab07SMatt Macy 	umode_t dm_mode;
903f6cab07SMatt Macy 	int dm_type;
913f6cab07SMatt Macy };
923f6cab07SMatt Macy 
933f6cab07SMatt Macy static int
943f6cab07SMatt Macy debugfs_attr(PFS_ATTR_ARGS)
953f6cab07SMatt Macy {
963f6cab07SMatt Macy 	struct dentry_meta *dm;
973f6cab07SMatt Macy 
983f6cab07SMatt Macy 	dm = pn->pn_data;
993f6cab07SMatt Macy 
1003f6cab07SMatt Macy 	vap->va_mode = dm->dm_mode;
1013f6cab07SMatt Macy 	return (0);
1023f6cab07SMatt Macy }
1033f6cab07SMatt Macy 
1043f6cab07SMatt Macy static int
1053f6cab07SMatt Macy debugfs_destroy(PFS_DESTROY_ARGS)
1063f6cab07SMatt Macy {
1073f6cab07SMatt Macy 	struct dentry_meta *dm;
1083f6cab07SMatt Macy 
1093f6cab07SMatt Macy 	dm = pn->pn_data;
1103f6cab07SMatt Macy 	if (dm->dm_type == DM_SYMLINK)
1113f6cab07SMatt Macy 		free(dm->dm_data, M_DFSINT);
1123f6cab07SMatt Macy 
1133f6cab07SMatt Macy 	free(dm, M_DFSINT);
1143f6cab07SMatt Macy 	return (0);
1153f6cab07SMatt Macy }
1163f6cab07SMatt Macy 
1173f6cab07SMatt Macy static int
1183f6cab07SMatt Macy debugfs_fill(PFS_FILL_ARGS)
1193f6cab07SMatt Macy {
1203f6cab07SMatt Macy 	struct dentry_meta *d;
12188a29d89SHans Petter Selasky 	struct linux_file lf = {};
1223f6cab07SMatt Macy 	struct vnode vn;
123f697b943SJake Freeland 	char *buf;
1243f6cab07SMatt Macy 	int rc;
125f697b943SJake Freeland 	off_t off = 0;
1263f6cab07SMatt Macy 
1273f6cab07SMatt Macy 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
1283f6cab07SMatt Macy 		return (rc);
129f697b943SJake Freeland 
130f697b943SJake Freeland 	d = pn->pn_data;
1313f6cab07SMatt Macy 	vn.v_data = d->dm_data;
132f697b943SJake Freeland 
1333f6cab07SMatt Macy 	rc = d->dm_fops->open(&vn, &lf);
1343f6cab07SMatt Macy 	if (rc < 0) {
1353f6cab07SMatt Macy #ifdef INVARIANTS
1363f6cab07SMatt Macy 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
1373f6cab07SMatt Macy #endif
1383f6cab07SMatt Macy 		return (-rc);
1393f6cab07SMatt Macy 	}
140f697b943SJake Freeland 
14168ec2949SHans Petter Selasky 	rc = -ENODEV;
142f697b943SJake Freeland 	if (uio->uio_rw == UIO_READ && d->dm_fops->read) {
143f697b943SJake Freeland 		rc = -ENOMEM;
144f697b943SJake Freeland 		buf = (char *) malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
145f697b943SJake Freeland 		if (buf != NULL) {
146f697b943SJake Freeland 			rc = d->dm_fops->read(&lf, buf, sb->s_size, &off);
147f697b943SJake Freeland 			if (rc > 0)
148f697b943SJake Freeland 				sbuf_bcpy(sb, buf, strlen(buf));
149f697b943SJake Freeland 
150f697b943SJake Freeland 			free(buf, M_DFSINT);
15103f1cf9fSJohannes Lundberg 		}
152f697b943SJake Freeland 	} else if (uio->uio_rw == UIO_WRITE && d->dm_fops->write) {
153f697b943SJake Freeland 		sbuf_finish(sb);
154f697b943SJake Freeland 		rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb), &off);
155f697b943SJake Freeland 	}
156f697b943SJake Freeland 
1573f6cab07SMatt Macy 	if (d->dm_fops->release)
1583f6cab07SMatt Macy 		d->dm_fops->release(&vn, &lf);
1593f6cab07SMatt Macy 	else
1603f6cab07SMatt Macy 		single_release(&vn, &lf);
1613f6cab07SMatt Macy 
1623f6cab07SMatt Macy 	if (rc < 0) {
1633f6cab07SMatt Macy #ifdef INVARIANTS
1643f6cab07SMatt Macy 		printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
1653f6cab07SMatt Macy #endif
1663f6cab07SMatt Macy 		return (-rc);
1673f6cab07SMatt Macy 	}
1683f6cab07SMatt Macy 	return (0);
1693f6cab07SMatt Macy }
1703f6cab07SMatt Macy 
1713f6cab07SMatt Macy static int
1723f6cab07SMatt Macy debugfs_fill_data(PFS_FILL_ARGS)
1733f6cab07SMatt Macy {
1743f6cab07SMatt Macy 	struct dentry_meta *dm;
1753f6cab07SMatt Macy 
1763f6cab07SMatt Macy 	dm = pn->pn_data;
1773f6cab07SMatt Macy 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
1783f6cab07SMatt Macy 	return (0);
1793f6cab07SMatt Macy }
1803f6cab07SMatt Macy 
1813f6cab07SMatt Macy struct dentry *
1823f6cab07SMatt Macy debugfs_create_file(const char *name, umode_t mode,
1833f6cab07SMatt Macy     struct dentry *parent, void *data,
1843f6cab07SMatt Macy     const struct file_operations *fops)
1853f6cab07SMatt Macy {
1863f6cab07SMatt Macy 	struct dentry_meta *dm;
1873f6cab07SMatt Macy 	struct dentry *dnode;
1883f6cab07SMatt Macy 	struct pfs_node *pnode;
1893f6cab07SMatt Macy 	int flags;
1903f6cab07SMatt Macy 
1913f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
1923f6cab07SMatt Macy 	if (dm == NULL)
1933f6cab07SMatt Macy 		return (NULL);
1943f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
1953f6cab07SMatt Macy 	dm->dm_fops = fops;
1963f6cab07SMatt Macy 	dm->dm_data = data;
1973f6cab07SMatt Macy 	dm->dm_mode = mode;
1983f6cab07SMatt Macy 	dm->dm_type = DM_FILE;
1993f6cab07SMatt Macy 	if (parent != NULL)
2003f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2013f6cab07SMatt Macy 	else
2023f6cab07SMatt Macy 		pnode = debugfs_root;
2033f6cab07SMatt Macy 
2043f6cab07SMatt Macy 	flags = fops->write ? PFS_RDWR : PFS_RD;
2053f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
2063f6cab07SMatt Macy 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
2073f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2083f6cab07SMatt Macy 		free(dm, M_DFSINT);
2093f6cab07SMatt Macy 		return (NULL);
2103f6cab07SMatt Macy 	}
2113f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2123f6cab07SMatt Macy 
2133f6cab07SMatt Macy 	return (dnode);
2143f6cab07SMatt Macy }
2153f6cab07SMatt Macy 
216f697b943SJake Freeland /*
217f697b943SJake Freeland  * NOTE: Files created with the _unsafe moniker will not be protected from
218f697b943SJake Freeland  * debugfs core file removals. It is the responsibility of @fops to protect
219f697b943SJake Freeland  * its file using debugfs_file_get() and debugfs_file_put().
220f697b943SJake Freeland  *
221f697b943SJake Freeland  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
222f697b943SJake Freeland  * of writing. Therefore there is no difference between functions with _unsafe
223f697b943SJake Freeland  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
224f697b943SJake Freeland  * exist only for Linux compatibility.
225f697b943SJake Freeland  */
226f697b943SJake Freeland struct dentry *
227f697b943SJake Freeland debugfs_create_file_unsafe(const char *name, umode_t mode,
228f697b943SJake Freeland     struct dentry *parent, void *data,
229f697b943SJake Freeland     const struct file_operations *fops)
230f697b943SJake Freeland {
231f697b943SJake Freeland 	return (debugfs_create_file(name, mode, parent, data, fops));
232f697b943SJake Freeland }
233f697b943SJake Freeland 
234f697b943SJake Freeland struct dentry *
235f697b943SJake Freeland debugfs_create_mode_unsafe(const char *name, umode_t mode,
236f697b943SJake Freeland     struct dentry *parent, void *data,
237f697b943SJake Freeland     const struct file_operations *fops,
238f697b943SJake Freeland     const struct file_operations *fops_ro,
239f697b943SJake Freeland     const struct file_operations *fops_wo)
240f697b943SJake Freeland {
241f697b943SJake Freeland 	umode_t read = mode & S_IRUGO;
242f697b943SJake Freeland 	umode_t write = mode & S_IWUGO;
243f697b943SJake Freeland 
244f697b943SJake Freeland 	if (read && !write)
245f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
246f697b943SJake Freeland 
247f697b943SJake Freeland 	if (write && !read)
248f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
249f697b943SJake Freeland 
250f697b943SJake Freeland 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
251f697b943SJake Freeland }
252f697b943SJake Freeland 
2533f6cab07SMatt Macy struct dentry *
2543f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2553f6cab07SMatt Macy {
2563f6cab07SMatt Macy 	struct dentry_meta *dm;
2573f6cab07SMatt Macy 	struct dentry *dnode;
2583f6cab07SMatt Macy 	struct pfs_node *pnode;
2593f6cab07SMatt Macy 
2603f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2613f6cab07SMatt Macy 	if (dm == NULL)
2623f6cab07SMatt Macy 		return (NULL);
2633f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2643f6cab07SMatt Macy 	dm->dm_mode = 0700;
2653f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2663f6cab07SMatt Macy 	if (parent != NULL)
2673f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2683f6cab07SMatt Macy 	else
2693f6cab07SMatt Macy 		pnode = debugfs_root;
2703f6cab07SMatt Macy 
2713f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2723f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2733f6cab07SMatt Macy 		free(dm, M_DFSINT);
2743f6cab07SMatt Macy 		return (NULL);
2753f6cab07SMatt Macy 	}
2763f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2773f6cab07SMatt Macy 	return (dnode);
2783f6cab07SMatt Macy }
2793f6cab07SMatt Macy 
2803f6cab07SMatt Macy struct dentry *
2813f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2823f6cab07SMatt Macy     const char *dest)
2833f6cab07SMatt Macy {
2843f6cab07SMatt Macy 	struct dentry_meta *dm;
2853f6cab07SMatt Macy 	struct dentry *dnode;
2863f6cab07SMatt Macy 	struct pfs_node *pnode;
2873f6cab07SMatt Macy 	void *data;
2883f6cab07SMatt Macy 
2893f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
2903f6cab07SMatt Macy 	if (data == NULL)
2913f6cab07SMatt Macy 		return (NULL);
2923f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2933f6cab07SMatt Macy 	if (dm == NULL)
2943f6cab07SMatt Macy 		goto fail1;
2953f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2963f6cab07SMatt Macy 	dm->dm_mode = 0700;
2973f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
2983f6cab07SMatt Macy 	dm->dm_data = data;
2993f6cab07SMatt Macy 	if (parent != NULL)
3003f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
3013f6cab07SMatt Macy 	else
3023f6cab07SMatt Macy 		pnode = debugfs_root;
3033f6cab07SMatt Macy 
3043f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
3053f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
3063f6cab07SMatt Macy 		goto fail;
3073f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
3083f6cab07SMatt Macy 	return (dnode);
3093f6cab07SMatt Macy  fail:
3103f6cab07SMatt Macy 	free(dm, M_DFSINT);
3113f6cab07SMatt Macy  fail1:
3123f6cab07SMatt Macy 	free(data, M_DFSINT);
3133f6cab07SMatt Macy 	return (NULL);
3143f6cab07SMatt Macy }
3153f6cab07SMatt Macy 
3163f6cab07SMatt Macy void
3173f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
3183f6cab07SMatt Macy {
3193f6cab07SMatt Macy 	if (dnode == NULL)
3203f6cab07SMatt Macy 		return;
3213f6cab07SMatt Macy 
3223f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3233f6cab07SMatt Macy }
3243f6cab07SMatt Macy 
3253f6cab07SMatt Macy void
3263f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
3273f6cab07SMatt Macy {
3283f6cab07SMatt Macy 	if (dnode == NULL)
3293f6cab07SMatt Macy 		return;
3303f6cab07SMatt Macy 
3313f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3323f6cab07SMatt Macy }
3333f6cab07SMatt Macy 
3343f6cab07SMatt Macy static int
335f697b943SJake Freeland debugfs_bool_get(void *data, uint64_t *ullval)
336f697b943SJake Freeland {
337f697b943SJake Freeland 	bool *bval = data;
338f697b943SJake Freeland 
339f697b943SJake Freeland 	if (*bval)
340f697b943SJake Freeland 		*ullval = 1;
341f697b943SJake Freeland 	else
342f697b943SJake Freeland 		*ullval = 0;
343f697b943SJake Freeland 
344f697b943SJake Freeland 	return (0);
345f697b943SJake Freeland }
346f697b943SJake Freeland 
347f697b943SJake Freeland static int
348f697b943SJake Freeland debugfs_bool_set(void *data, uint64_t ullval)
349f697b943SJake Freeland {
350f697b943SJake Freeland 	bool *bval = data;
351f697b943SJake Freeland 
352f697b943SJake Freeland 	if (ullval)
353f697b943SJake Freeland 		*bval = 1;
354f697b943SJake Freeland 	else
355f697b943SJake Freeland 		*bval = 0;
356f697b943SJake Freeland 
357f697b943SJake Freeland 	return (0);
358f697b943SJake Freeland }
359f697b943SJake Freeland 
360f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
361f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
362f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
363f697b943SJake Freeland 
364f697b943SJake Freeland void
365f697b943SJake Freeland debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
366f697b943SJake Freeland {
367*976aa07aSJean-Sébastien Pédron 
368f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
369f697b943SJake Freeland 	    &fops_bool_ro, &fops_bool_wo);
370f697b943SJake Freeland }
371f697b943SJake Freeland 
3720fce2dc1SBjoern A. Zeeb 
3730fce2dc1SBjoern A. Zeeb static int
3740fce2dc1SBjoern A. Zeeb debugfs_u8_get(void *data, uint64_t *value)
3750fce2dc1SBjoern A. Zeeb {
3760fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3770fce2dc1SBjoern A. Zeeb 	*value = *u8data;
3780fce2dc1SBjoern A. Zeeb 	return (0);
3790fce2dc1SBjoern A. Zeeb }
3800fce2dc1SBjoern A. Zeeb 
3810fce2dc1SBjoern A. Zeeb static int
3820fce2dc1SBjoern A. Zeeb debugfs_u8_set(void *data, uint64_t value)
3830fce2dc1SBjoern A. Zeeb {
3840fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
3850fce2dc1SBjoern A. Zeeb 	*u8data = (uint8_t)value;
3860fce2dc1SBjoern A. Zeeb 	return (0);
3870fce2dc1SBjoern A. Zeeb }
3880fce2dc1SBjoern A. Zeeb 
3890fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
3900fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
3910fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
3920fce2dc1SBjoern A. Zeeb 
3930fce2dc1SBjoern A. Zeeb void
3940fce2dc1SBjoern A. Zeeb debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
3950fce2dc1SBjoern A. Zeeb {
396*976aa07aSJean-Sébastien Pédron 
3970fce2dc1SBjoern A. Zeeb 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
3980fce2dc1SBjoern A. Zeeb 	    &fops_u8_ro, &fops_u8_wo);
3990fce2dc1SBjoern A. Zeeb }
4000fce2dc1SBjoern A. Zeeb 
401*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
402*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
403*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
404*976aa07aSJean-Sébastien Pédron 
405*976aa07aSJean-Sébastien Pédron void
406*976aa07aSJean-Sébastien Pédron debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
407*976aa07aSJean-Sébastien Pédron {
408*976aa07aSJean-Sébastien Pédron 
409*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
410*976aa07aSJean-Sébastien Pédron 	    &fops_x8_ro, &fops_x8_wo);
411*976aa07aSJean-Sébastien Pédron }
412*976aa07aSJean-Sébastien Pédron 
413*976aa07aSJean-Sébastien Pédron 
414*976aa07aSJean-Sébastien Pédron static int
415*976aa07aSJean-Sébastien Pédron debugfs_u16_get(void *data, uint64_t *value)
416*976aa07aSJean-Sébastien Pédron {
417*976aa07aSJean-Sébastien Pédron 	uint16_t *u16data = data;
418*976aa07aSJean-Sébastien Pédron 	*value = *u16data;
419*976aa07aSJean-Sébastien Pédron 	return (0);
420*976aa07aSJean-Sébastien Pédron }
421*976aa07aSJean-Sébastien Pédron 
422*976aa07aSJean-Sébastien Pédron static int
423*976aa07aSJean-Sébastien Pédron debugfs_u16_set(void *data, uint64_t value)
424*976aa07aSJean-Sébastien Pédron {
425*976aa07aSJean-Sébastien Pédron 	uint16_t *u16data = data;
426*976aa07aSJean-Sébastien Pédron 	*u16data = (uint16_t)value;
427*976aa07aSJean-Sébastien Pédron 	return (0);
428*976aa07aSJean-Sébastien Pédron }
429*976aa07aSJean-Sébastien Pédron 
430*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
431*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
432*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
433*976aa07aSJean-Sébastien Pédron 
434*976aa07aSJean-Sébastien Pédron void
435*976aa07aSJean-Sébastien Pédron debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
436*976aa07aSJean-Sébastien Pédron {
437*976aa07aSJean-Sébastien Pédron 
438*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
439*976aa07aSJean-Sébastien Pédron 	    &fops_u16_ro, &fops_u16_wo);
440*976aa07aSJean-Sébastien Pédron }
441*976aa07aSJean-Sébastien Pédron 
442*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
443*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
444*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
445*976aa07aSJean-Sébastien Pédron 
446*976aa07aSJean-Sébastien Pédron void
447*976aa07aSJean-Sébastien Pédron debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
448*976aa07aSJean-Sébastien Pédron {
449*976aa07aSJean-Sébastien Pédron 
450*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
451*976aa07aSJean-Sébastien Pédron 	    &fops_x16_ro, &fops_x16_wo);
452*976aa07aSJean-Sébastien Pédron }
453*976aa07aSJean-Sébastien Pédron 
454*976aa07aSJean-Sébastien Pédron 
455*976aa07aSJean-Sébastien Pédron static int
456*976aa07aSJean-Sébastien Pédron debugfs_u32_get(void *data, uint64_t *value)
457*976aa07aSJean-Sébastien Pédron {
458*976aa07aSJean-Sébastien Pédron 	uint32_t *u32data = data;
459*976aa07aSJean-Sébastien Pédron 	*value = *u32data;
460*976aa07aSJean-Sébastien Pédron 	return (0);
461*976aa07aSJean-Sébastien Pédron }
462*976aa07aSJean-Sébastien Pédron 
463*976aa07aSJean-Sébastien Pédron static int
464*976aa07aSJean-Sébastien Pédron debugfs_u32_set(void *data, uint64_t value)
465*976aa07aSJean-Sébastien Pédron {
466*976aa07aSJean-Sébastien Pédron 	uint32_t *u32data = data;
467*976aa07aSJean-Sébastien Pédron 	*u32data = (uint32_t)value;
468*976aa07aSJean-Sébastien Pédron 	return (0);
469*976aa07aSJean-Sébastien Pédron }
470*976aa07aSJean-Sébastien Pédron 
471*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
472*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
473*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
474*976aa07aSJean-Sébastien Pédron 
475*976aa07aSJean-Sébastien Pédron void
476*976aa07aSJean-Sébastien Pédron debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
477*976aa07aSJean-Sébastien Pédron {
478*976aa07aSJean-Sébastien Pédron 
479*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
480*976aa07aSJean-Sébastien Pédron 	    &fops_u32_ro, &fops_u32_wo);
481*976aa07aSJean-Sébastien Pédron }
482*976aa07aSJean-Sébastien Pédron 
483*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
484*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
485*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
486*976aa07aSJean-Sébastien Pédron 
487*976aa07aSJean-Sébastien Pédron void
488*976aa07aSJean-Sébastien Pédron debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
489*976aa07aSJean-Sébastien Pédron {
490*976aa07aSJean-Sébastien Pédron 
491*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
492*976aa07aSJean-Sébastien Pédron 	    &fops_x32_ro, &fops_x32_wo);
493*976aa07aSJean-Sébastien Pédron }
494*976aa07aSJean-Sébastien Pédron 
495*976aa07aSJean-Sébastien Pédron 
496*976aa07aSJean-Sébastien Pédron static int
497*976aa07aSJean-Sébastien Pédron debugfs_u64_get(void *data, uint64_t *value)
498*976aa07aSJean-Sébastien Pédron {
499*976aa07aSJean-Sébastien Pédron 	uint64_t *u64data = data;
500*976aa07aSJean-Sébastien Pédron 	*value = *u64data;
501*976aa07aSJean-Sébastien Pédron 	return (0);
502*976aa07aSJean-Sébastien Pédron }
503*976aa07aSJean-Sébastien Pédron 
504*976aa07aSJean-Sébastien Pédron static int
505*976aa07aSJean-Sébastien Pédron debugfs_u64_set(void *data, uint64_t value)
506*976aa07aSJean-Sébastien Pédron {
507*976aa07aSJean-Sébastien Pédron 	uint64_t *u64data = data;
508*976aa07aSJean-Sébastien Pédron 	*u64data = (uint64_t)value;
509*976aa07aSJean-Sébastien Pédron 	return (0);
510*976aa07aSJean-Sébastien Pédron }
511*976aa07aSJean-Sébastien Pédron 
512*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
513*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
514*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
515*976aa07aSJean-Sébastien Pédron 
516*976aa07aSJean-Sébastien Pédron void
517*976aa07aSJean-Sébastien Pédron debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
518*976aa07aSJean-Sébastien Pédron {
519*976aa07aSJean-Sébastien Pédron 
520*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
521*976aa07aSJean-Sébastien Pédron 	    &fops_u64_ro, &fops_u64_wo);
522*976aa07aSJean-Sébastien Pédron }
523*976aa07aSJean-Sébastien Pédron 
524*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
525*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
526*976aa07aSJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
527*976aa07aSJean-Sébastien Pédron 
528*976aa07aSJean-Sébastien Pédron void
529*976aa07aSJean-Sébastien Pédron debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
530*976aa07aSJean-Sébastien Pédron {
531*976aa07aSJean-Sébastien Pédron 
532*976aa07aSJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
533*976aa07aSJean-Sébastien Pédron 	    &fops_x64_ro, &fops_x64_wo);
534*976aa07aSJean-Sébastien Pédron }
535*976aa07aSJean-Sébastien Pédron 
5360fce2dc1SBjoern A. Zeeb 
537f697b943SJake Freeland static int
538f697b943SJake Freeland debugfs_ulong_get(void *data, uint64_t *value)
539f697b943SJake Freeland {
540f697b943SJake Freeland 	uint64_t *uldata = data;
541f697b943SJake Freeland 	*value = *uldata;
542f697b943SJake Freeland 	return (0);
543f697b943SJake Freeland }
544f697b943SJake Freeland 
545f697b943SJake Freeland static int
546f697b943SJake Freeland debugfs_ulong_set(void *data, uint64_t value)
547f697b943SJake Freeland {
548f697b943SJake Freeland 	uint64_t *uldata = data;
549f697b943SJake Freeland 	*uldata = value;
550f697b943SJake Freeland 	return (0);
551f697b943SJake Freeland }
552f697b943SJake Freeland 
553f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
554f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
555f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
556f697b943SJake Freeland 
557f697b943SJake Freeland void
558f697b943SJake Freeland debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
559f697b943SJake Freeland {
560*976aa07aSJean-Sébastien Pédron 
561f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
562f697b943SJake Freeland 	    &fops_ulong_ro, &fops_ulong_wo);
563f697b943SJake Freeland }
564f697b943SJake Freeland 
5650fce2dc1SBjoern A. Zeeb 
566f2044a30SJean-Sébastien Pédron static int
567f2044a30SJean-Sébastien Pédron debugfs_atomic_t_get(void *data, uint64_t *value)
568f2044a30SJean-Sébastien Pédron {
569f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
570f2044a30SJean-Sébastien Pédron 	*value = atomic_read(atomic_data);
571f2044a30SJean-Sébastien Pédron 	return (0);
572f2044a30SJean-Sébastien Pédron }
573f2044a30SJean-Sébastien Pédron 
574f2044a30SJean-Sébastien Pédron static int
575f2044a30SJean-Sébastien Pédron debugfs_atomic_t_set(void *data, uint64_t value)
576f2044a30SJean-Sébastien Pédron {
577f2044a30SJean-Sébastien Pédron 	atomic_t *atomic_data = data;
578f2044a30SJean-Sébastien Pédron 	atomic_set(atomic_data, (int)value);
579f2044a30SJean-Sébastien Pédron 	return (0);
580f2044a30SJean-Sébastien Pédron }
581f2044a30SJean-Sébastien Pédron 
582f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
583f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
584f2044a30SJean-Sébastien Pédron DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
585f2044a30SJean-Sébastien Pédron 
586f2044a30SJean-Sébastien Pédron void
587f2044a30SJean-Sébastien Pédron debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
588f2044a30SJean-Sébastien Pédron {
589f2044a30SJean-Sébastien Pédron 
590f2044a30SJean-Sébastien Pédron 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
591f2044a30SJean-Sébastien Pédron 	    &fops_atomic_t_ro, &fops_atomic_t_wo);
592f2044a30SJean-Sébastien Pédron }
593f2044a30SJean-Sébastien Pédron 
594f2044a30SJean-Sébastien Pédron 
5950fce2dc1SBjoern A. Zeeb static ssize_t
5960fce2dc1SBjoern A. Zeeb fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
5970fce2dc1SBjoern A. Zeeb {
5980fce2dc1SBjoern A. Zeeb 	struct debugfs_blob_wrapper *blob;
5990fce2dc1SBjoern A. Zeeb 
6000fce2dc1SBjoern A. Zeeb 	blob = filp->private_data;
6010fce2dc1SBjoern A. Zeeb 	if (blob == NULL)
6020fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
6030fce2dc1SBjoern A. Zeeb 	if (blob->size == 0 || blob->data == NULL)
6040fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
6050fce2dc1SBjoern A. Zeeb 
6060fce2dc1SBjoern A. Zeeb 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
6070fce2dc1SBjoern A. Zeeb }
6080fce2dc1SBjoern A. Zeeb 
6090fce2dc1SBjoern A. Zeeb static int
6100fce2dc1SBjoern A. Zeeb fops_blob_open(struct inode *inode, struct file *filp)
6110fce2dc1SBjoern A. Zeeb {
612*976aa07aSJean-Sébastien Pédron 
6130fce2dc1SBjoern A. Zeeb 	return (simple_open(inode, filp));
6140fce2dc1SBjoern A. Zeeb }
6150fce2dc1SBjoern A. Zeeb 
6160fce2dc1SBjoern A. Zeeb static const struct file_operations __fops_blob_ro = {
6170fce2dc1SBjoern A. Zeeb 	.owner = THIS_MODULE,
6180fce2dc1SBjoern A. Zeeb 	.open = fops_blob_open,
6190fce2dc1SBjoern A. Zeeb 	.read = fops_blob_read,
6200fce2dc1SBjoern A. Zeeb 	.llseek = no_llseek
6210fce2dc1SBjoern A. Zeeb };
6220fce2dc1SBjoern A. Zeeb 
6230fce2dc1SBjoern A. Zeeb struct dentry *
6240fce2dc1SBjoern A. Zeeb debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
6250fce2dc1SBjoern A. Zeeb     struct debugfs_blob_wrapper *value)
6260fce2dc1SBjoern A. Zeeb {
6270fce2dc1SBjoern A. Zeeb 	/* Blobs are read-only. */
6280fce2dc1SBjoern A. Zeeb 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
6290fce2dc1SBjoern A. Zeeb }
6300fce2dc1SBjoern A. Zeeb 
6310fce2dc1SBjoern A. Zeeb 
632f697b943SJake Freeland static int
633f697b943SJake Freeland lindebugfs_init(PFS_INIT_ARGS)
6343f6cab07SMatt Macy {
6353f6cab07SMatt Macy 
6363f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
63746888dedSMark Johnston 
63846888dedSMark Johnston 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
63946888dedSMark Johnston 
6403f6cab07SMatt Macy 	return (0);
6413f6cab07SMatt Macy }
6423f6cab07SMatt Macy 
6433f6cab07SMatt Macy static int
644f697b943SJake Freeland lindebugfs_uninit(PFS_INIT_ARGS)
6453f6cab07SMatt Macy {
646*976aa07aSJean-Sébastien Pédron 
6473f6cab07SMatt Macy 	return (0);
6483f6cab07SMatt Macy }
6493f6cab07SMatt Macy 
650f697b943SJake Freeland PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
65103f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
652