xref: /freebsd/sys/compat/lindebugfs/lindebugfs.c (revision 0fce2dc1573019d0732f33fa7c26cc228655d3e8)
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 
723f6cab07SMatt Macy #include <linux/compat.h>
73f697b943SJake Freeland #include <linux/debugfs.h>
74f697b943SJake Freeland #include <linux/fs.h>
753f6cab07SMatt Macy 
763f6cab07SMatt Macy MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
773f6cab07SMatt Macy 
783f6cab07SMatt Macy static struct pfs_node *debugfs_root;
793f6cab07SMatt Macy 
803f6cab07SMatt Macy #define DM_SYMLINK 0x1
813f6cab07SMatt Macy #define DM_DIR 0x2
823f6cab07SMatt Macy #define DM_FILE 0x3
833f6cab07SMatt Macy 
843f6cab07SMatt Macy struct dentry_meta {
853f6cab07SMatt Macy 	struct dentry dm_dnode;
863f6cab07SMatt Macy 	const struct file_operations *dm_fops;
873f6cab07SMatt Macy 	void *dm_data;
883f6cab07SMatt Macy 	umode_t dm_mode;
893f6cab07SMatt Macy 	int dm_type;
903f6cab07SMatt Macy };
913f6cab07SMatt Macy 
923f6cab07SMatt Macy static int
933f6cab07SMatt Macy debugfs_attr(PFS_ATTR_ARGS)
943f6cab07SMatt Macy {
953f6cab07SMatt Macy 	struct dentry_meta *dm;
963f6cab07SMatt Macy 
973f6cab07SMatt Macy 	dm = pn->pn_data;
983f6cab07SMatt Macy 
993f6cab07SMatt Macy 	vap->va_mode = dm->dm_mode;
1003f6cab07SMatt Macy 	return (0);
1013f6cab07SMatt Macy }
1023f6cab07SMatt Macy 
1033f6cab07SMatt Macy static int
1043f6cab07SMatt Macy debugfs_destroy(PFS_DESTROY_ARGS)
1053f6cab07SMatt Macy {
1063f6cab07SMatt Macy 	struct dentry_meta *dm;
1073f6cab07SMatt Macy 
1083f6cab07SMatt Macy 	dm = pn->pn_data;
1093f6cab07SMatt Macy 	if (dm->dm_type == DM_SYMLINK)
1103f6cab07SMatt Macy 		free(dm->dm_data, M_DFSINT);
1113f6cab07SMatt Macy 
1123f6cab07SMatt Macy 	free(dm, M_DFSINT);
1133f6cab07SMatt Macy 	return (0);
1143f6cab07SMatt Macy }
1153f6cab07SMatt Macy 
1163f6cab07SMatt Macy static int
1173f6cab07SMatt Macy debugfs_fill(PFS_FILL_ARGS)
1183f6cab07SMatt Macy {
1193f6cab07SMatt Macy 	struct dentry_meta *d;
12088a29d89SHans Petter Selasky 	struct linux_file lf = {};
1213f6cab07SMatt Macy 	struct vnode vn;
122f697b943SJake Freeland 	char *buf;
1233f6cab07SMatt Macy 	int rc;
124f697b943SJake Freeland 	off_t off = 0;
1253f6cab07SMatt Macy 
1263f6cab07SMatt Macy 	if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
1273f6cab07SMatt Macy 		return (rc);
128f697b943SJake Freeland 
129f697b943SJake Freeland 	d = pn->pn_data;
1303f6cab07SMatt Macy 	vn.v_data = d->dm_data;
131f697b943SJake Freeland 
1323f6cab07SMatt Macy 	rc = d->dm_fops->open(&vn, &lf);
1333f6cab07SMatt Macy 	if (rc < 0) {
1343f6cab07SMatt Macy #ifdef INVARIANTS
1353f6cab07SMatt Macy 		printf("%s:%d open failed with %d\n", __FUNCTION__, __LINE__, rc);
1363f6cab07SMatt Macy #endif
1373f6cab07SMatt Macy 		return (-rc);
1383f6cab07SMatt Macy 	}
139f697b943SJake Freeland 
14068ec2949SHans Petter Selasky 	rc = -ENODEV;
141f697b943SJake Freeland 	if (uio->uio_rw == UIO_READ && d->dm_fops->read) {
142f697b943SJake Freeland 		rc = -ENOMEM;
143f697b943SJake Freeland 		buf = (char *) malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
144f697b943SJake Freeland 		if (buf != NULL) {
145f697b943SJake Freeland 			rc = d->dm_fops->read(&lf, buf, sb->s_size, &off);
146f697b943SJake Freeland 			if (rc > 0)
147f697b943SJake Freeland 				sbuf_bcpy(sb, buf, strlen(buf));
148f697b943SJake Freeland 
149f697b943SJake Freeland 			free(buf, M_DFSINT);
15003f1cf9fSJohannes Lundberg 		}
151f697b943SJake Freeland 	} else if (uio->uio_rw == UIO_WRITE && d->dm_fops->write) {
152f697b943SJake Freeland 		sbuf_finish(sb);
153f697b943SJake Freeland 		rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb), &off);
154f697b943SJake Freeland 	}
155f697b943SJake Freeland 
1563f6cab07SMatt Macy 	if (d->dm_fops->release)
1573f6cab07SMatt Macy 		d->dm_fops->release(&vn, &lf);
1583f6cab07SMatt Macy 	else
1593f6cab07SMatt Macy 		single_release(&vn, &lf);
1603f6cab07SMatt Macy 
1613f6cab07SMatt Macy 	if (rc < 0) {
1623f6cab07SMatt Macy #ifdef INVARIANTS
1633f6cab07SMatt Macy 		printf("%s:%d read/write failed with %d\n", __FUNCTION__, __LINE__, rc);
1643f6cab07SMatt Macy #endif
1653f6cab07SMatt Macy 		return (-rc);
1663f6cab07SMatt Macy 	}
1673f6cab07SMatt Macy 	return (0);
1683f6cab07SMatt Macy }
1693f6cab07SMatt Macy 
1703f6cab07SMatt Macy static int
1713f6cab07SMatt Macy debugfs_fill_data(PFS_FILL_ARGS)
1723f6cab07SMatt Macy {
1733f6cab07SMatt Macy 	struct dentry_meta *dm;
1743f6cab07SMatt Macy 
1753f6cab07SMatt Macy 	dm = pn->pn_data;
1763f6cab07SMatt Macy 	sbuf_printf(sb, "%s", (char *)dm->dm_data);
1773f6cab07SMatt Macy 	return (0);
1783f6cab07SMatt Macy }
1793f6cab07SMatt Macy 
1803f6cab07SMatt Macy struct dentry *
1813f6cab07SMatt Macy debugfs_create_file(const char *name, umode_t mode,
1823f6cab07SMatt Macy     struct dentry *parent, void *data,
1833f6cab07SMatt Macy     const struct file_operations *fops)
1843f6cab07SMatt Macy {
1853f6cab07SMatt Macy 	struct dentry_meta *dm;
1863f6cab07SMatt Macy 	struct dentry *dnode;
1873f6cab07SMatt Macy 	struct pfs_node *pnode;
1883f6cab07SMatt Macy 	int flags;
1893f6cab07SMatt Macy 
1903f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
1913f6cab07SMatt Macy 	if (dm == NULL)
1923f6cab07SMatt Macy 		return (NULL);
1933f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
1943f6cab07SMatt Macy 	dm->dm_fops = fops;
1953f6cab07SMatt Macy 	dm->dm_data = data;
1963f6cab07SMatt Macy 	dm->dm_mode = mode;
1973f6cab07SMatt Macy 	dm->dm_type = DM_FILE;
1983f6cab07SMatt Macy 	if (parent != NULL)
1993f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2003f6cab07SMatt Macy 	else
2013f6cab07SMatt Macy 		pnode = debugfs_root;
2023f6cab07SMatt Macy 
2033f6cab07SMatt Macy 	flags = fops->write ? PFS_RDWR : PFS_RD;
2043f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
2053f6cab07SMatt Macy 	    debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
2063f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2073f6cab07SMatt Macy 		free(dm, M_DFSINT);
2083f6cab07SMatt Macy 		return (NULL);
2093f6cab07SMatt Macy 	}
2103f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2113f6cab07SMatt Macy 
2123f6cab07SMatt Macy 	return (dnode);
2133f6cab07SMatt Macy }
2143f6cab07SMatt Macy 
215f697b943SJake Freeland /*
216f697b943SJake Freeland  * NOTE: Files created with the _unsafe moniker will not be protected from
217f697b943SJake Freeland  * debugfs core file removals. It is the responsibility of @fops to protect
218f697b943SJake Freeland  * its file using debugfs_file_get() and debugfs_file_put().
219f697b943SJake Freeland  *
220f697b943SJake Freeland  * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
221f697b943SJake Freeland  * of writing. Therefore there is no difference between functions with _unsafe
222f697b943SJake Freeland  * and functions without _unsafe when using lindebugfs. Functions with _unsafe
223f697b943SJake Freeland  * exist only for Linux compatibility.
224f697b943SJake Freeland  */
225f697b943SJake Freeland struct dentry *
226f697b943SJake Freeland debugfs_create_file_unsafe(const char *name, umode_t mode,
227f697b943SJake Freeland     struct dentry *parent, void *data,
228f697b943SJake Freeland     const struct file_operations *fops)
229f697b943SJake Freeland {
230f697b943SJake Freeland 	return (debugfs_create_file(name, mode, parent, data, fops));
231f697b943SJake Freeland }
232f697b943SJake Freeland 
233f697b943SJake Freeland struct dentry *
234f697b943SJake Freeland debugfs_create_mode_unsafe(const char *name, umode_t mode,
235f697b943SJake Freeland     struct dentry *parent, void *data,
236f697b943SJake Freeland     const struct file_operations *fops,
237f697b943SJake Freeland     const struct file_operations *fops_ro,
238f697b943SJake Freeland     const struct file_operations *fops_wo)
239f697b943SJake Freeland {
240f697b943SJake Freeland 	umode_t read = mode & S_IRUGO;
241f697b943SJake Freeland 	umode_t write = mode & S_IWUGO;
242f697b943SJake Freeland 
243f697b943SJake Freeland 	if (read && !write)
244f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
245f697b943SJake Freeland 
246f697b943SJake Freeland 	if (write && !read)
247f697b943SJake Freeland 		return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
248f697b943SJake Freeland 
249f697b943SJake Freeland 	return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
250f697b943SJake Freeland }
251f697b943SJake Freeland 
2523f6cab07SMatt Macy struct dentry *
2533f6cab07SMatt Macy debugfs_create_dir(const char *name, struct dentry *parent)
2543f6cab07SMatt Macy {
2553f6cab07SMatt Macy 	struct dentry_meta *dm;
2563f6cab07SMatt Macy 	struct dentry *dnode;
2573f6cab07SMatt Macy 	struct pfs_node *pnode;
2583f6cab07SMatt Macy 
2593f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2603f6cab07SMatt Macy 	if (dm == NULL)
2613f6cab07SMatt Macy 		return (NULL);
2623f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2633f6cab07SMatt Macy 	dm->dm_mode = 0700;
2643f6cab07SMatt Macy 	dm->dm_type = DM_DIR;
2653f6cab07SMatt Macy 	if (parent != NULL)
2663f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
2673f6cab07SMatt Macy 	else
2683f6cab07SMatt Macy 		pnode = debugfs_root;
2693f6cab07SMatt Macy 
2703f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
2713f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL) {
2723f6cab07SMatt Macy 		free(dm, M_DFSINT);
2733f6cab07SMatt Macy 		return (NULL);
2743f6cab07SMatt Macy 	}
2753f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
2763f6cab07SMatt Macy 	return (dnode);
2773f6cab07SMatt Macy }
2783f6cab07SMatt Macy 
2793f6cab07SMatt Macy struct dentry *
2803f6cab07SMatt Macy debugfs_create_symlink(const char *name, struct dentry *parent,
2813f6cab07SMatt Macy     const char *dest)
2823f6cab07SMatt Macy {
2833f6cab07SMatt Macy 	struct dentry_meta *dm;
2843f6cab07SMatt Macy 	struct dentry *dnode;
2853f6cab07SMatt Macy 	struct pfs_node *pnode;
2863f6cab07SMatt Macy 	void *data;
2873f6cab07SMatt Macy 
2883f6cab07SMatt Macy 	data = strdup_flags(dest, M_DFSINT, M_NOWAIT);
2893f6cab07SMatt Macy 	if (data == NULL)
2903f6cab07SMatt Macy 		return (NULL);
2913f6cab07SMatt Macy 	dm = malloc(sizeof(*dm), M_DFSINT, M_NOWAIT | M_ZERO);
2923f6cab07SMatt Macy 	if (dm == NULL)
2933f6cab07SMatt Macy 		goto fail1;
2943f6cab07SMatt Macy 	dnode = &dm->dm_dnode;
2953f6cab07SMatt Macy 	dm->dm_mode = 0700;
2963f6cab07SMatt Macy 	dm->dm_type = DM_SYMLINK;
2973f6cab07SMatt Macy 	dm->dm_data = data;
2983f6cab07SMatt Macy 	if (parent != NULL)
2993f6cab07SMatt Macy 		pnode = parent->d_pfs_node;
3003f6cab07SMatt Macy 	else
3013f6cab07SMatt Macy 		pnode = debugfs_root;
3023f6cab07SMatt Macy 
3033f6cab07SMatt Macy 	dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
3043f6cab07SMatt Macy 	if (dnode->d_pfs_node == NULL)
3053f6cab07SMatt Macy 		goto fail;
3063f6cab07SMatt Macy 	dnode->d_pfs_node->pn_data = dm;
3073f6cab07SMatt Macy 	return (dnode);
3083f6cab07SMatt Macy  fail:
3093f6cab07SMatt Macy 	free(dm, M_DFSINT);
3103f6cab07SMatt Macy  fail1:
3113f6cab07SMatt Macy 	free(data, M_DFSINT);
3123f6cab07SMatt Macy 	return (NULL);
3133f6cab07SMatt Macy }
3143f6cab07SMatt Macy 
3153f6cab07SMatt Macy void
3163f6cab07SMatt Macy debugfs_remove(struct dentry *dnode)
3173f6cab07SMatt Macy {
3183f6cab07SMatt Macy 	if (dnode == NULL)
3193f6cab07SMatt Macy 		return;
3203f6cab07SMatt Macy 
3213f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3223f6cab07SMatt Macy }
3233f6cab07SMatt Macy 
3243f6cab07SMatt Macy void
3253f6cab07SMatt Macy debugfs_remove_recursive(struct dentry *dnode)
3263f6cab07SMatt Macy {
3273f6cab07SMatt Macy 	if (dnode == NULL)
3283f6cab07SMatt Macy 		return;
3293f6cab07SMatt Macy 
3303f6cab07SMatt Macy 	pfs_destroy(dnode->d_pfs_node);
3313f6cab07SMatt Macy }
3323f6cab07SMatt Macy 
3333f6cab07SMatt Macy static int
334f697b943SJake Freeland debugfs_bool_get(void *data, uint64_t *ullval)
335f697b943SJake Freeland {
336f697b943SJake Freeland 	bool *bval = data;
337f697b943SJake Freeland 
338f697b943SJake Freeland 	if (*bval)
339f697b943SJake Freeland 		*ullval = 1;
340f697b943SJake Freeland 	else
341f697b943SJake Freeland 		*ullval = 0;
342f697b943SJake Freeland 
343f697b943SJake Freeland 	return (0);
344f697b943SJake Freeland }
345f697b943SJake Freeland 
346f697b943SJake Freeland static int
347f697b943SJake Freeland debugfs_bool_set(void *data, uint64_t ullval)
348f697b943SJake Freeland {
349f697b943SJake Freeland 	bool *bval = data;
350f697b943SJake Freeland 
351f697b943SJake Freeland 	if (ullval)
352f697b943SJake Freeland 		*bval = 1;
353f697b943SJake Freeland 	else
354f697b943SJake Freeland 		*bval = 0;
355f697b943SJake Freeland 
356f697b943SJake Freeland 	return (0);
357f697b943SJake Freeland }
358f697b943SJake Freeland 
359f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
360f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
361f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
362f697b943SJake Freeland 
363f697b943SJake Freeland void
364f697b943SJake Freeland debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
365f697b943SJake Freeland {
366f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
367f697b943SJake Freeland 	    &fops_bool_ro, &fops_bool_wo);
368f697b943SJake Freeland }
369f697b943SJake Freeland 
370*0fce2dc1SBjoern A. Zeeb 
371*0fce2dc1SBjoern A. Zeeb static int
372*0fce2dc1SBjoern A. Zeeb debugfs_u8_get(void *data, uint64_t *value)
373*0fce2dc1SBjoern A. Zeeb {
374*0fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
375*0fce2dc1SBjoern A. Zeeb 	*value = *u8data;
376*0fce2dc1SBjoern A. Zeeb 	return (0);
377*0fce2dc1SBjoern A. Zeeb }
378*0fce2dc1SBjoern A. Zeeb 
379*0fce2dc1SBjoern A. Zeeb static int
380*0fce2dc1SBjoern A. Zeeb debugfs_u8_set(void *data, uint64_t value)
381*0fce2dc1SBjoern A. Zeeb {
382*0fce2dc1SBjoern A. Zeeb 	uint8_t *u8data = data;
383*0fce2dc1SBjoern A. Zeeb 	*u8data = (uint8_t)value;
384*0fce2dc1SBjoern A. Zeeb 	return (0);
385*0fce2dc1SBjoern A. Zeeb }
386*0fce2dc1SBjoern A. Zeeb 
387*0fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
388*0fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
389*0fce2dc1SBjoern A. Zeeb DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
390*0fce2dc1SBjoern A. Zeeb 
391*0fce2dc1SBjoern A. Zeeb void
392*0fce2dc1SBjoern A. Zeeb debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
393*0fce2dc1SBjoern A. Zeeb {
394*0fce2dc1SBjoern A. Zeeb 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
395*0fce2dc1SBjoern A. Zeeb 	    &fops_u8_ro, &fops_u8_wo);
396*0fce2dc1SBjoern A. Zeeb }
397*0fce2dc1SBjoern A. Zeeb 
398*0fce2dc1SBjoern A. Zeeb 
399f697b943SJake Freeland static int
400f697b943SJake Freeland debugfs_ulong_get(void *data, uint64_t *value)
401f697b943SJake Freeland {
402f697b943SJake Freeland 	uint64_t *uldata = data;
403f697b943SJake Freeland 	*value = *uldata;
404f697b943SJake Freeland 	return (0);
405f697b943SJake Freeland }
406f697b943SJake Freeland 
407f697b943SJake Freeland static int
408f697b943SJake Freeland debugfs_ulong_set(void *data, uint64_t value)
409f697b943SJake Freeland {
410f697b943SJake Freeland 	uint64_t *uldata = data;
411f697b943SJake Freeland 	*uldata = value;
412f697b943SJake Freeland 	return (0);
413f697b943SJake Freeland }
414f697b943SJake Freeland 
415f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
416f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
417f697b943SJake Freeland DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
418f697b943SJake Freeland 
419f697b943SJake Freeland void
420f697b943SJake Freeland debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
421f697b943SJake Freeland {
422f697b943SJake Freeland 	debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
423f697b943SJake Freeland 	    &fops_ulong_ro, &fops_ulong_wo);
424f697b943SJake Freeland }
425f697b943SJake Freeland 
426*0fce2dc1SBjoern A. Zeeb 
427*0fce2dc1SBjoern A. Zeeb static ssize_t
428*0fce2dc1SBjoern A. Zeeb fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
429*0fce2dc1SBjoern A. Zeeb {
430*0fce2dc1SBjoern A. Zeeb 	struct debugfs_blob_wrapper *blob;
431*0fce2dc1SBjoern A. Zeeb 
432*0fce2dc1SBjoern A. Zeeb 	blob = filp->private_data;
433*0fce2dc1SBjoern A. Zeeb 	if (blob == NULL)
434*0fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
435*0fce2dc1SBjoern A. Zeeb 	if (blob->size == 0 || blob->data == NULL)
436*0fce2dc1SBjoern A. Zeeb 		return (-EINVAL);
437*0fce2dc1SBjoern A. Zeeb 
438*0fce2dc1SBjoern A. Zeeb 	return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
439*0fce2dc1SBjoern A. Zeeb }
440*0fce2dc1SBjoern A. Zeeb 
441*0fce2dc1SBjoern A. Zeeb static int
442*0fce2dc1SBjoern A. Zeeb fops_blob_open(struct inode *inode, struct file *filp)
443*0fce2dc1SBjoern A. Zeeb {
444*0fce2dc1SBjoern A. Zeeb 	return (simple_open(inode, filp));
445*0fce2dc1SBjoern A. Zeeb }
446*0fce2dc1SBjoern A. Zeeb 
447*0fce2dc1SBjoern A. Zeeb static const struct file_operations __fops_blob_ro = {
448*0fce2dc1SBjoern A. Zeeb 	.owner = THIS_MODULE,
449*0fce2dc1SBjoern A. Zeeb 	.open = fops_blob_open,
450*0fce2dc1SBjoern A. Zeeb 	.read = fops_blob_read,
451*0fce2dc1SBjoern A. Zeeb 	.llseek = no_llseek
452*0fce2dc1SBjoern A. Zeeb };
453*0fce2dc1SBjoern A. Zeeb 
454*0fce2dc1SBjoern A. Zeeb struct dentry *
455*0fce2dc1SBjoern A. Zeeb debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
456*0fce2dc1SBjoern A. Zeeb     struct debugfs_blob_wrapper *value)
457*0fce2dc1SBjoern A. Zeeb {
458*0fce2dc1SBjoern A. Zeeb 	/* Blobs are read-only. */
459*0fce2dc1SBjoern A. Zeeb 	return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
460*0fce2dc1SBjoern A. Zeeb }
461*0fce2dc1SBjoern A. Zeeb 
462*0fce2dc1SBjoern A. Zeeb 
463f697b943SJake Freeland static int
464f697b943SJake Freeland lindebugfs_init(PFS_INIT_ARGS)
4653f6cab07SMatt Macy {
4663f6cab07SMatt Macy 
4673f6cab07SMatt Macy 	debugfs_root = pi->pi_root;
46846888dedSMark Johnston 
46946888dedSMark Johnston 	(void)debugfs_create_symlink("kcov", NULL, "/dev/kcov");
47046888dedSMark Johnston 
4713f6cab07SMatt Macy 	return (0);
4723f6cab07SMatt Macy }
4733f6cab07SMatt Macy 
4743f6cab07SMatt Macy static int
475f697b943SJake Freeland lindebugfs_uninit(PFS_INIT_ARGS)
4763f6cab07SMatt Macy {
4773f6cab07SMatt Macy 	return (0);
4783f6cab07SMatt Macy }
4793f6cab07SMatt Macy 
480f697b943SJake Freeland PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
48103f1cf9fSJohannes Lundberg MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
482