162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/init.h> 362306a36Sopenharmony_ci#include <linux/seq_file.h> 462306a36Sopenharmony_ci#include <linux/fs.h> 562306a36Sopenharmony_ci#include <linux/mm.h> 662306a36Sopenharmony_ci#include <linux/proc_fs.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <xen/interface/platform.h> 962306a36Sopenharmony_ci#include <asm/xen/hypercall.h> 1062306a36Sopenharmony_ci#include <xen/xen-ops.h> 1162306a36Sopenharmony_ci#include "xenfs.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define XEN_KSYM_NAME_LEN 127 /* Hypervisor may have different name length */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct xensyms { 1762306a36Sopenharmony_ci struct xen_platform_op op; 1862306a36Sopenharmony_ci char *name; 1962306a36Sopenharmony_ci uint32_t namelen; 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Grab next output page from the hypervisor */ 2362306a36Sopenharmony_cistatic int xensyms_next_sym(struct xensyms *xs) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci int ret; 2662306a36Sopenharmony_ci struct xenpf_symdata *symdata = &xs->op.u.symdata; 2762306a36Sopenharmony_ci uint64_t symnum; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci memset(xs->name, 0, xs->namelen); 3062306a36Sopenharmony_ci symdata->namelen = xs->namelen; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci symnum = symdata->symnum; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci ret = HYPERVISOR_platform_op(&xs->op); 3562306a36Sopenharmony_ci if (ret < 0) 3662306a36Sopenharmony_ci return ret; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* 3962306a36Sopenharmony_ci * If hypervisor's symbol didn't fit into the buffer then allocate 4062306a36Sopenharmony_ci * a larger buffer and try again. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci if (unlikely(symdata->namelen > xs->namelen)) { 4362306a36Sopenharmony_ci kfree(xs->name); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci xs->namelen = symdata->namelen; 4662306a36Sopenharmony_ci xs->name = kzalloc(xs->namelen, GFP_KERNEL); 4762306a36Sopenharmony_ci if (!xs->name) 4862306a36Sopenharmony_ci return -ENOMEM; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci set_xen_guest_handle(symdata->name, xs->name); 5162306a36Sopenharmony_ci symdata->symnum--; /* Rewind */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ret = HYPERVISOR_platform_op(&xs->op); 5462306a36Sopenharmony_ci if (ret < 0) 5562306a36Sopenharmony_ci return ret; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (symdata->symnum == symnum) 5962306a36Sopenharmony_ci /* End of symbols */ 6062306a36Sopenharmony_ci return 1; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void *xensyms_start(struct seq_file *m, loff_t *pos) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct xensyms *xs = m->private; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci xs->op.u.symdata.symnum = *pos; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (xensyms_next_sym(xs)) 7262306a36Sopenharmony_ci return NULL; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return m->private; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void *xensyms_next(struct seq_file *m, void *p, loff_t *pos) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct xensyms *xs = m->private; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci xs->op.u.symdata.symnum = ++(*pos); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (xensyms_next_sym(xs)) 8462306a36Sopenharmony_ci return NULL; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return p; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int xensyms_show(struct seq_file *m, void *p) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct xensyms *xs = m->private; 9262306a36Sopenharmony_ci struct xenpf_symdata *symdata = &xs->op.u.symdata; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci seq_printf(m, "%016llx %c %s\n", symdata->address, 9562306a36Sopenharmony_ci symdata->type, xs->name); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void xensyms_stop(struct seq_file *m, void *p) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const struct seq_operations xensyms_seq_ops = { 10562306a36Sopenharmony_ci .start = xensyms_start, 10662306a36Sopenharmony_ci .next = xensyms_next, 10762306a36Sopenharmony_ci .show = xensyms_show, 10862306a36Sopenharmony_ci .stop = xensyms_stop, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int xensyms_open(struct inode *inode, struct file *file) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct seq_file *m; 11462306a36Sopenharmony_ci struct xensyms *xs; 11562306a36Sopenharmony_ci int ret; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ret = seq_open_private(file, &xensyms_seq_ops, 11862306a36Sopenharmony_ci sizeof(struct xensyms)); 11962306a36Sopenharmony_ci if (ret) 12062306a36Sopenharmony_ci return ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci m = file->private_data; 12362306a36Sopenharmony_ci xs = m->private; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci xs->namelen = XEN_KSYM_NAME_LEN + 1; 12662306a36Sopenharmony_ci xs->name = kzalloc(xs->namelen, GFP_KERNEL); 12762306a36Sopenharmony_ci if (!xs->name) { 12862306a36Sopenharmony_ci seq_release_private(inode, file); 12962306a36Sopenharmony_ci return -ENOMEM; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci set_xen_guest_handle(xs->op.u.symdata.name, xs->name); 13262306a36Sopenharmony_ci xs->op.cmd = XENPF_get_symbol; 13362306a36Sopenharmony_ci xs->op.u.symdata.namelen = xs->namelen; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int xensyms_release(struct inode *inode, struct file *file) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct seq_file *m = file->private_data; 14162306a36Sopenharmony_ci struct xensyms *xs = m->private; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci kfree(xs->name); 14462306a36Sopenharmony_ci return seq_release_private(inode, file); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciconst struct file_operations xensyms_ops = { 14862306a36Sopenharmony_ci .open = xensyms_open, 14962306a36Sopenharmony_ci .read = seq_read, 15062306a36Sopenharmony_ci .llseek = seq_lseek, 15162306a36Sopenharmony_ci .release = xensyms_release 15262306a36Sopenharmony_ci}; 153