Linux Audio

Check our new training course

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