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