brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · b799bc7 Raw
153 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/init.h>3#include <linux/seq_file.h>4#include <linux/fs.h>5#include <linux/mm.h>6#include <linux/proc_fs.h>7#include <linux/slab.h>8#include <xen/interface/platform.h>9#include <asm/xen/hypercall.h>10#include <xen/xen-ops.h>11#include "xenfs.h"12 13 14#define XEN_KSYM_NAME_LEN 127 /* Hypervisor may have different name length */15 16struct xensyms {17	struct xen_platform_op op;18	char *name;19	uint32_t namelen;20};21 22/* Grab next output page from the hypervisor */23static int xensyms_next_sym(struct xensyms *xs)24{25	int ret;26	struct xenpf_symdata *symdata = &xs->op.u.symdata;27	uint64_t symnum;28 29	memset(xs->name, 0, xs->namelen);30	symdata->namelen = xs->namelen;31 32	symnum = symdata->symnum;33 34	ret = HYPERVISOR_platform_op(&xs->op);35	if (ret < 0)36		return ret;37 38	/*39	 * If hypervisor's symbol didn't fit into the buffer then allocate40	 * a larger buffer and try again.41	 */42	if (unlikely(symdata->namelen > xs->namelen)) {43		kfree(xs->name);44 45		xs->namelen = symdata->namelen;46		xs->name = kzalloc(xs->namelen, GFP_KERNEL);47		if (!xs->name)48			return -ENOMEM;49 50		set_xen_guest_handle(symdata->name, xs->name);51		symdata->symnum--; /* Rewind */52 53		ret = HYPERVISOR_platform_op(&xs->op);54		if (ret < 0)55			return ret;56	}57 58	if (symdata->symnum == symnum)59		/* End of symbols */60		return 1;61 62	return 0;63}64 65static void *xensyms_start(struct seq_file *m, loff_t *pos)66{67	struct xensyms *xs = m->private;68 69	xs->op.u.symdata.symnum = *pos;70 71	if (xensyms_next_sym(xs))72		return NULL;73 74	return m->private;75}76 77static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos)78{79	struct xensyms *xs = m->private;80 81	xs->op.u.symdata.symnum = ++(*pos);82 83	if (xensyms_next_sym(xs))84		return NULL;85 86	return p;87}88 89static int xensyms_show(struct seq_file *m, void *p)90{91	struct xensyms *xs = m->private;92	struct xenpf_symdata *symdata = &xs->op.u.symdata;93 94	seq_printf(m, "%016llx %c %s\n", symdata->address,95		   symdata->type, xs->name);96 97	return 0;98}99 100static void xensyms_stop(struct seq_file *m, void *p)101{102}103 104static const struct seq_operations xensyms_seq_ops = {105	.start = xensyms_start,106	.next = xensyms_next,107	.show = xensyms_show,108	.stop = xensyms_stop,109};110 111static int xensyms_open(struct inode *inode, struct file *file)112{113	struct seq_file *m;114	struct xensyms *xs;115	int ret;116 117	ret = seq_open_private(file, &xensyms_seq_ops,118			       sizeof(struct xensyms));119	if (ret)120		return ret;121 122	m = file->private_data;123	xs = m->private;124 125	xs->namelen = XEN_KSYM_NAME_LEN + 1;126	xs->name = kzalloc(xs->namelen, GFP_KERNEL);127	if (!xs->name) {128		seq_release_private(inode, file);129		return -ENOMEM;130	}131	set_xen_guest_handle(xs->op.u.symdata.name, xs->name);132	xs->op.cmd = XENPF_get_symbol;133	xs->op.u.symdata.namelen = xs->namelen;134 135	return 0;136}137 138static int xensyms_release(struct inode *inode, struct file *file)139{140	struct seq_file *m = file->private_data;141	struct xensyms *xs = m->private;142 143	kfree(xs->name);144	return seq_release_private(inode, file);145}146 147const struct file_operations xensyms_ops = {148	.open = xensyms_open,149	.read = seq_read,150	.llseek = seq_lseek,151	.release = xensyms_release152};153