Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2#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 allocate
 40	 * 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 = (struct xensyms *)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 = (struct xensyms *)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 = (struct xensyms *)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 = (struct xensyms *)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 = (struct xensyms *)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_release
152};