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 | |
16 | struct xensyms { |
17 | struct xen_platform_op op; |
18 | char *name; |
19 | uint32_t namelen; |
20 | }; |
21 | |
22 | /* Grab next output page from the hypervisor */ |
23 | static 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(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(objp: xs->name); |
44 | |
45 | xs->namelen = symdata->namelen; |
46 | xs->name = kzalloc(size: 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(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 | |
65 | static 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 | |
77 | static 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 | |
89 | static 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, fmt: "%016llx %c %s\n" , symdata->address, |
95 | symdata->type, xs->name); |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | static void xensyms_stop(struct seq_file *m, void *p) |
101 | { |
102 | } |
103 | |
104 | static 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 | |
111 | static 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(size: 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 | |
138 | static 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(objp: xs->name); |
144 | return seq_release_private(inode, file); |
145 | } |
146 | |
147 | const struct file_operations xensyms_ops = { |
148 | .open = xensyms_open, |
149 | .read = seq_read, |
150 | .llseek = seq_lseek, |
151 | .release = xensyms_release |
152 | }; |
153 | |