mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-31 04:01:48 -04:00
xen: features and fixes for 4.3-rc0
- Convert xen-blkfront to the multiqueue API
- [arm] Support binding event channels to different VCPUs.
- [x86] Support > 512 GiB in a PV guests (off by default as such a
guest cannot be migrated with the current toolstack).
- [x86] PMU support for PV dom0 (limited support for using perf with
Xen and other guests).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABAgAGBQJV7wIdAAoJEFxbo/MsZsTR0hEH/04HTKLKGnSJpZ5WbMPxqZxE
UqGlvhvVWNAmFocZmbPcEi9T1qtcFrX5pM55JQr6UmAp3ovYsT2q1Q1kKaOaawks
pSfc/YEH3oQW5VUQ9Lm9Ru5Z8Btox0WrzRREO92OF36UOgUOBOLkGsUfOwDinNIM
lSk2djbYwDYAsoeC3PHB32wwMI//Lz6B/9ZVXcyL6ULynt1ULdspETjGnptRPZa7
JTB5L4/soioKOn18HDwwOhKmvaFUPQv9Odnv7dc85XwZreajhM/KMu3qFbMDaF/d
WVB1NMeCBdQYgjOrUjrmpyr5uTMySiQEG54cplrEKinfeZgKlEyjKvjcAfJfiac=
=Ktjl
-----END PGP SIGNATURE-----
Merge tag 'for-linus-4.3-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen updates from David Vrabel:
"Xen features and fixes for 4.3:
- Convert xen-blkfront to the multiqueue API
- [arm] Support binding event channels to different VCPUs.
- [x86] Support > 512 GiB in a PV guests (off by default as such a
guest cannot be migrated with the current toolstack).
- [x86] PMU support for PV dom0 (limited support for using perf with
Xen and other guests)"
* tag 'for-linus-4.3-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: (33 commits)
xen: switch extra memory accounting to use pfns
xen: limit memory to architectural maximum
xen: avoid another early crash of memory limited dom0
xen: avoid early crash of memory limited dom0
arm/xen: Remove helpers which are PV specific
xen/x86: Don't try to set PCE bit in CR4
xen/PMU: PMU emulation code
xen/PMU: Intercept PMU-related MSR and APIC accesses
xen/PMU: Describe vendor-specific PMU registers
xen/PMU: Initialization code for Xen PMU
xen/PMU: Sysfs interface for setting Xen PMU mode
xen: xensyms support
xen: remove no longer needed p2m.h
xen: allow more than 512 GB of RAM for 64 bit pv-domains
xen: move p2m list if conflicting with e820 map
xen: add explicit memblock_reserve() calls for special pages
mm: provide early_memremap_ro to establish read-only mapping
xen: check for initrd conflicting with e820 map
xen: check pre-allocated page tables for conflict with memory map
xen: check for kernel memory conflicting with memory layout
...
This commit is contained in:
commit
752240e74d
42 changed files with 2229 additions and 363 deletions
|
|
@ -280,4 +280,15 @@ config XEN_ACPI
|
|||
def_bool y
|
||||
depends on X86 && ACPI
|
||||
|
||||
config XEN_SYMS
|
||||
bool "Xen symbols"
|
||||
depends on X86 && XEN_DOM0 && XENFS
|
||||
default y if KALLSYMS
|
||||
help
|
||||
Exports hypervisor symbols (along with their types and addresses) via
|
||||
/proc/xen/xensyms file, similar to /proc/kallsyms
|
||||
|
||||
config XEN_HAVE_VPMU
|
||||
bool
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -638,9 +638,9 @@ static int __init balloon_init(void)
|
|||
* regions (see arch/x86/xen/setup.c).
|
||||
*/
|
||||
for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++)
|
||||
if (xen_extra_mem[i].size)
|
||||
balloon_add_region(PFN_UP(xen_extra_mem[i].start),
|
||||
PFN_DOWN(xen_extra_mem[i].size));
|
||||
if (xen_extra_mem[i].n_pfns)
|
||||
balloon_add_region(xen_extra_mem[i].start_pfn,
|
||||
xen_extra_mem[i].n_pfns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1301,11 +1301,7 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
|
|||
if (!VALID_EVTCHN(evtchn))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Events delivered via platform PCI interrupts are always
|
||||
* routed to vcpu 0 and hence cannot be rebound.
|
||||
*/
|
||||
if (xen_hvm_domain() && !xen_have_vector_callback)
|
||||
if (!xen_support_evtchn_rebind())
|
||||
return -1;
|
||||
|
||||
/* Send future instances of this interrupt to other vcpu. */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
#include <xen/xenbus.h>
|
||||
#include <xen/interface/xen.h>
|
||||
#include <xen/interface/version.h>
|
||||
#ifdef CONFIG_XEN_HAVE_VPMU
|
||||
#include <xen/interface/xenpmu.h>
|
||||
#endif
|
||||
|
||||
#define HYPERVISOR_ATTR_RO(_name) \
|
||||
static struct hyp_sysfs_attr _name##_attr = __ATTR_RO(_name)
|
||||
|
|
@ -368,6 +371,126 @@ static void xen_properties_destroy(void)
|
|||
sysfs_remove_group(hypervisor_kobj, &xen_properties_group);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_HAVE_VPMU
|
||||
struct pmu_mode {
|
||||
const char *name;
|
||||
uint32_t mode;
|
||||
};
|
||||
|
||||
static struct pmu_mode pmu_modes[] = {
|
||||
{"off", XENPMU_MODE_OFF},
|
||||
{"self", XENPMU_MODE_SELF},
|
||||
{"hv", XENPMU_MODE_HV},
|
||||
{"all", XENPMU_MODE_ALL}
|
||||
};
|
||||
|
||||
static ssize_t pmu_mode_store(struct hyp_sysfs_attr *attr,
|
||||
const char *buffer, size_t len)
|
||||
{
|
||||
int ret;
|
||||
struct xen_pmu_params xp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
|
||||
if (strncmp(buffer, pmu_modes[i].name, len - 1) == 0) {
|
||||
xp.val = pmu_modes[i].mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(pmu_modes))
|
||||
return -EINVAL;
|
||||
|
||||
xp.version.maj = XENPMU_VER_MAJ;
|
||||
xp.version.min = XENPMU_VER_MIN;
|
||||
ret = HYPERVISOR_xenpmu_op(XENPMU_mode_set, &xp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t pmu_mode_show(struct hyp_sysfs_attr *attr, char *buffer)
|
||||
{
|
||||
int ret;
|
||||
struct xen_pmu_params xp;
|
||||
int i;
|
||||
uint32_t mode;
|
||||
|
||||
xp.version.maj = XENPMU_VER_MAJ;
|
||||
xp.version.min = XENPMU_VER_MIN;
|
||||
ret = HYPERVISOR_xenpmu_op(XENPMU_mode_get, &xp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mode = (uint32_t)xp.val;
|
||||
for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
|
||||
if (mode == pmu_modes[i].mode)
|
||||
return sprintf(buffer, "%s\n", pmu_modes[i].name);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
HYPERVISOR_ATTR_RW(pmu_mode);
|
||||
|
||||
static ssize_t pmu_features_store(struct hyp_sysfs_attr *attr,
|
||||
const char *buffer, size_t len)
|
||||
{
|
||||
int ret;
|
||||
uint32_t features;
|
||||
struct xen_pmu_params xp;
|
||||
|
||||
ret = kstrtou32(buffer, 0, &features);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xp.val = features;
|
||||
xp.version.maj = XENPMU_VER_MAJ;
|
||||
xp.version.min = XENPMU_VER_MIN;
|
||||
ret = HYPERVISOR_xenpmu_op(XENPMU_feature_set, &xp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t pmu_features_show(struct hyp_sysfs_attr *attr, char *buffer)
|
||||
{
|
||||
int ret;
|
||||
struct xen_pmu_params xp;
|
||||
|
||||
xp.version.maj = XENPMU_VER_MAJ;
|
||||
xp.version.min = XENPMU_VER_MIN;
|
||||
ret = HYPERVISOR_xenpmu_op(XENPMU_feature_get, &xp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buffer, "0x%x\n", (uint32_t)xp.val);
|
||||
}
|
||||
HYPERVISOR_ATTR_RW(pmu_features);
|
||||
|
||||
static struct attribute *xen_pmu_attrs[] = {
|
||||
&pmu_mode_attr.attr,
|
||||
&pmu_features_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group xen_pmu_group = {
|
||||
.name = "pmu",
|
||||
.attrs = xen_pmu_attrs,
|
||||
};
|
||||
|
||||
static int __init xen_pmu_init(void)
|
||||
{
|
||||
return sysfs_create_group(hypervisor_kobj, &xen_pmu_group);
|
||||
}
|
||||
|
||||
static void xen_pmu_destroy(void)
|
||||
{
|
||||
sysfs_remove_group(hypervisor_kobj, &xen_pmu_group);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init hyper_sysfs_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -390,7 +513,15 @@ static int __init hyper_sysfs_init(void)
|
|||
ret = xen_properties_init();
|
||||
if (ret)
|
||||
goto prop_out;
|
||||
|
||||
#ifdef CONFIG_XEN_HAVE_VPMU
|
||||
if (xen_initial_domain()) {
|
||||
ret = xen_pmu_init();
|
||||
if (ret) {
|
||||
xen_properties_destroy();
|
||||
goto prop_out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
goto out;
|
||||
|
||||
prop_out:
|
||||
|
|
@ -407,6 +538,9 @@ out:
|
|||
|
||||
static void __exit hyper_sysfs_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_XEN_HAVE_VPMU
|
||||
xen_pmu_destroy();
|
||||
#endif
|
||||
xen_properties_destroy();
|
||||
xen_compilation_destroy();
|
||||
xen_sysfs_uuid_destroy();
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ obj-$(CONFIG_XENFS) += xenfs.o
|
|||
|
||||
xenfs-y = super.o
|
||||
xenfs-$(CONFIG_XEN_DOM0) += xenstored.o
|
||||
xenfs-$(CONFIG_XEN_SYMS) += xensyms.o
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
{ "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR },
|
||||
{ "xsd_kva", &xsd_kva_file_ops, S_IRUSR|S_IWUSR},
|
||||
{ "xsd_port", &xsd_port_file_ops, S_IRUSR|S_IWUSR},
|
||||
#ifdef CONFIG_XEN_SYMS
|
||||
{ "xensyms", &xensyms_ops, S_IRUSR},
|
||||
#endif
|
||||
{""},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@
|
|||
|
||||
extern const struct file_operations xsd_kva_file_ops;
|
||||
extern const struct file_operations xsd_port_file_ops;
|
||||
extern const struct file_operations xensyms_ops;
|
||||
|
||||
#endif /* _XENFS_XENBUS_H */
|
||||
|
|
|
|||
152
drivers/xen/xenfs/xensyms.c
Normal file
152
drivers/xen/xenfs/xensyms.c
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <xen/interface/platform.h>
|
||||
#include <asm/xen/hypercall.h>
|
||||
#include <xen/xen-ops.h>
|
||||
#include "xenfs.h"
|
||||
|
||||
|
||||
#define XEN_KSYM_NAME_LEN 127 /* Hypervisor may have different name length */
|
||||
|
||||
struct xensyms {
|
||||
struct xen_platform_op op;
|
||||
char *name;
|
||||
uint32_t namelen;
|
||||
};
|
||||
|
||||
/* Grab next output page from the hypervisor */
|
||||
static int xensyms_next_sym(struct xensyms *xs)
|
||||
{
|
||||
int ret;
|
||||
struct xenpf_symdata *symdata = &xs->op.u.symdata;
|
||||
uint64_t symnum;
|
||||
|
||||
memset(xs->name, 0, xs->namelen);
|
||||
symdata->namelen = xs->namelen;
|
||||
|
||||
symnum = symdata->symnum;
|
||||
|
||||
ret = HYPERVISOR_dom0_op(&xs->op);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If hypervisor's symbol didn't fit into the buffer then allocate
|
||||
* a larger buffer and try again.
|
||||
*/
|
||||
if (unlikely(symdata->namelen > xs->namelen)) {
|
||||
kfree(xs->name);
|
||||
|
||||
xs->namelen = symdata->namelen;
|
||||
xs->name = kzalloc(xs->namelen, GFP_KERNEL);
|
||||
if (!xs->name)
|
||||
return -ENOMEM;
|
||||
|
||||
set_xen_guest_handle(symdata->name, xs->name);
|
||||
symdata->symnum--; /* Rewind */
|
||||
|
||||
ret = HYPERVISOR_dom0_op(&xs->op);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (symdata->symnum == symnum)
|
||||
/* End of symbols */
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *xensyms_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
struct xensyms *xs = (struct xensyms *)m->private;
|
||||
|
||||
xs->op.u.symdata.symnum = *pos;
|
||||
|
||||
if (xensyms_next_sym(xs))
|
||||
return NULL;
|
||||
|
||||
return m->private;
|
||||
}
|
||||
|
||||
static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos)
|
||||
{
|
||||
struct xensyms *xs = (struct xensyms *)m->private;
|
||||
|
||||
xs->op.u.symdata.symnum = ++(*pos);
|
||||
|
||||
if (xensyms_next_sym(xs))
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int xensyms_show(struct seq_file *m, void *p)
|
||||
{
|
||||
struct xensyms *xs = (struct xensyms *)m->private;
|
||||
struct xenpf_symdata *symdata = &xs->op.u.symdata;
|
||||
|
||||
seq_printf(m, "%016llx %c %s\n", symdata->address,
|
||||
symdata->type, xs->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xensyms_stop(struct seq_file *m, void *p)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct seq_operations xensyms_seq_ops = {
|
||||
.start = xensyms_start,
|
||||
.next = xensyms_next,
|
||||
.show = xensyms_show,
|
||||
.stop = xensyms_stop,
|
||||
};
|
||||
|
||||
static int xensyms_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m;
|
||||
struct xensyms *xs;
|
||||
int ret;
|
||||
|
||||
ret = seq_open_private(file, &xensyms_seq_ops,
|
||||
sizeof(struct xensyms));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
m = file->private_data;
|
||||
xs = (struct xensyms *)m->private;
|
||||
|
||||
xs->namelen = XEN_KSYM_NAME_LEN + 1;
|
||||
xs->name = kzalloc(xs->namelen, GFP_KERNEL);
|
||||
if (!xs->name) {
|
||||
seq_release_private(inode, file);
|
||||
return -ENOMEM;
|
||||
}
|
||||
set_xen_guest_handle(xs->op.u.symdata.name, xs->name);
|
||||
xs->op.cmd = XENPF_get_symbol;
|
||||
xs->op.u.symdata.namelen = xs->namelen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xensyms_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m = file->private_data;
|
||||
struct xensyms *xs = (struct xensyms *)m->private;
|
||||
|
||||
kfree(xs->name);
|
||||
return seq_release_private(inode, file);
|
||||
}
|
||||
|
||||
const struct file_operations xensyms_ops = {
|
||||
.open = xensyms_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = xensyms_release
|
||||
};
|
||||
Loading…
Reference in a new issue