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