* [PATCH v17 01/23] common/symbols: Export hypervisor symbols to privileged guest
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
@ 2015-01-05 21:43 ` Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 02/23] x86/VPMU: Don't globally disable VPMU if initialization fails Boris Ostrovsky
` (22 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:43 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Export Xen's symbols as {<address><type><name>} triplet via new XENPF_get_symbol
hypercall
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/platform_hypercall.c | 28 +++++++++++++++++++
xen/common/symbols.c | 54 +++++++++++++++++++++++++++++++++++++
xen/include/public/platform.h | 19 +++++++++++++
xen/include/xen/symbols.h | 3 +++
xen/include/xlat.lst | 1 +
xen/xsm/flask/hooks.c | 4 +++
xen/xsm/flask/policy/access_vectors | 2 ++
7 files changed, 111 insertions(+)
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index 32f39b2..7b37960 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -23,6 +23,7 @@
#include <xen/cpu.h>
#include <xen/pmstat.h>
#include <xen/irq.h>
+#include <xen/symbols.h>
#include <asm/current.h>
#include <public/platform.h>
#include <acpi/cpufreq/processor_perf.h>
@@ -760,6 +761,33 @@ ret_t do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
}
break;
+ case XENPF_get_symbol:
+ {
+ static char name[KSYM_NAME_LEN + 1]; /* protected by xenpf_lock */
+ XEN_GUEST_HANDLE(char) nameh;
+ uint32_t namelen, copylen;
+
+ guest_from_compat_handle(nameh, op->u.symdata.name);
+
+ ret = xensyms_read(&op->u.symdata.symnum, &op->u.symdata.type,
+ &op->u.symdata.address, name);
+
+ namelen = strlen(name) + 1;
+
+ if ( namelen > op->u.symdata.namelen )
+ copylen = op->u.symdata.namelen;
+ else
+ copylen = namelen;
+
+ op->u.symdata.namelen = namelen;
+
+ if ( !ret && copy_to_guest(nameh, name, copylen) )
+ ret = -EFAULT;
+ if ( !ret && __copy_field_to_guest(u_xenpf_op, op, u.symdata) )
+ ret = -EFAULT;
+ }
+ break;
+
default:
ret = -ENOSYS;
break;
diff --git a/xen/common/symbols.c b/xen/common/symbols.c
index bc2fde6..2c0942d 100644
--- a/xen/common/symbols.c
+++ b/xen/common/symbols.c
@@ -17,6 +17,8 @@
#include <xen/lib.h>
#include <xen/string.h>
#include <xen/spinlock.h>
+#include <public/platform.h>
+#include <xen/guest_access.h>
#ifdef SYMBOLS_ORIGIN
extern const unsigned int symbols_offsets[1];
@@ -148,3 +150,55 @@ const char *symbols_lookup(unsigned long addr,
*offset = addr - symbols_address(low);
return namebuf;
}
+
+/*
+ * Get symbol type information. This is encoded as a single char at the
+ * beginning of the symbol name.
+ */
+static char symbols_get_symbol_type(unsigned int off)
+{
+ /*
+ * Get just the first code, look it up in the token table,
+ * and return the first char from this token.
+ */
+ return symbols_token_table[symbols_token_index[symbols_names[off + 1]]];
+}
+
+int xensyms_read(uint32_t *symnum, char *type,
+ uint64_t *address, char *name)
+{
+ /*
+ * Symbols are most likely accessed sequentially so we remember position
+ * from previous read. This can help us avoid the extra call to
+ * get_symbol_offset().
+ */
+ static uint64_t next_symbol, next_offset;
+ static DEFINE_SPINLOCK(symbols_mutex);
+
+ if ( *symnum > symbols_num_syms )
+ return -ERANGE;
+ if ( *symnum == symbols_num_syms )
+ {
+ /* No more symbols */
+ name[0] = '\0';
+ return 0;
+ }
+
+ spin_lock(&symbols_mutex);
+
+ if ( *symnum == 0 )
+ next_offset = next_symbol = 0;
+ if ( next_symbol != *symnum )
+ /* Non-sequential access */
+ next_offset = get_symbol_offset(*symnum);
+
+ *type = symbols_get_symbol_type(next_offset);
+ next_offset = symbols_expand_symbol(next_offset, name);
+ *address = symbols_offsets[*symnum] + SYMBOLS_ORIGIN;
+
+ next_symbol = ++*symnum;
+
+ spin_unlock(&symbols_mutex);
+
+ return 0;
+}
diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h
index 5c57615..6dd7732 100644
--- a/xen/include/public/platform.h
+++ b/xen/include/public/platform.h
@@ -560,6 +560,24 @@ struct xenpf_resource_op {
typedef struct xenpf_resource_op xenpf_resource_op_t;
DEFINE_XEN_GUEST_HANDLE(xenpf_resource_op_t);
+#define XENPF_get_symbol 62
+struct xenpf_symdata {
+ /* IN/OUT variables */
+ uint32_t namelen; /* IN: size of name buffer */
+ /* OUT: strlen(name) of hypervisor symbol (may be */
+ /* larger than what's been copied to guest) */
+ uint32_t symnum; /* IN: Symbol to read */
+ /* OUT: Next available symbol. If same as IN then */
+ /* we reached the end */
+
+ /* OUT variables */
+ XEN_GUEST_HANDLE(char) name;
+ uint64_t address;
+ char type;
+};
+typedef struct xenpf_symdata xenpf_symdata_t;
+DEFINE_XEN_GUEST_HANDLE(xenpf_symdata_t);
+
/*
* ` enum neg_errnoval
* ` HYPERVISOR_platform_op(const struct xen_platform_op*);
@@ -587,6 +605,7 @@ struct xen_platform_op {
struct xenpf_mem_hotadd mem_add;
struct xenpf_core_parking core_parking;
struct xenpf_resource_op resource_op;
+ struct xenpf_symdata symdata;
uint8_t pad[128];
} u;
};
diff --git a/xen/include/xen/symbols.h b/xen/include/xen/symbols.h
index 87cd77d..1fa0537 100644
--- a/xen/include/xen/symbols.h
+++ b/xen/include/xen/symbols.h
@@ -11,4 +11,7 @@ const char *symbols_lookup(unsigned long addr,
unsigned long *offset,
char *namebuf);
+int xensyms_read(uint32_t *symnum, char *type,
+ uint64_t *address, char *name);
+
#endif /*_XEN_SYMBOLS_H*/
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index 41b3e35..eb40aab 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -87,6 +87,7 @@
? processor_px platform.h
! psd_package platform.h
? xenpf_enter_acpi_sleep platform.h
+! xenpf_symdata platform.h
? xenpf_pcpuinfo platform.h
? xenpf_pcpu_version platform.h
? xenpf_resource_entry platform.h
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index d48463f..c589e49 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -1410,6 +1410,10 @@ static int flask_platform_op(uint32_t op)
return avc_current_has_perm(SECINITSID_XEN, SECCLASS_XEN2,
XEN2__RESOURCE_OP, NULL);
+ case XENPF_get_symbol:
+ return avc_has_perm(domain_sid(current->domain), SECINITSID_XEN,
+ SECCLASS_XEN2, XEN2__GET_SYMBOL, NULL);
+
default:
printk("flask_platform_op: Unknown op %d\n", op);
return -EPERM;
diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors
index 1da9f63..ed91c09 100644
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -83,6 +83,8 @@ class xen2
resource_op
# XEN_SYSCTL_psr_cmt_op
psr_cmt_op
+# XENPF_get_symbol
+ get_symbol
}
# Classes domain and domain2 consist of operations that a domain performs on
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 02/23] x86/VPMU: Don't globally disable VPMU if initialization fails.
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 01/23] common/symbols: Export hypervisor symbols to privileged guest Boris Ostrovsky
@ 2015-01-05 21:43 ` Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 03/23] x86/VPMU: Manage VPMU_CONTEXT_SAVE flag in vpmu_save_force() Boris Ostrovsky
` (21 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:43 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
The failure to initialize VPMU may be temporary so we shouldn'd disable VMPU
forever.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reported-by: Jan Beulich <jbeulich@suse.com>
---
xen/arch/x86/hvm/vpmu.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 37f0d9f..efb2279 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -218,6 +218,7 @@ void vpmu_initialise(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
uint8_t vendor = current_cpu_data.x86_vendor;
+ int ret;
if ( is_pvh_vcpu(v) )
return;
@@ -230,21 +231,25 @@ void vpmu_initialise(struct vcpu *v)
switch ( vendor )
{
case X86_VENDOR_AMD:
- if ( svm_vpmu_initialise(v, opt_vpmu_enabled) != 0 )
- opt_vpmu_enabled = 0;
+ ret = svm_vpmu_initialise(v, opt_vpmu_enabled);
break;
case X86_VENDOR_INTEL:
- if ( vmx_vpmu_initialise(v, opt_vpmu_enabled) != 0 )
- opt_vpmu_enabled = 0;
+ ret = vmx_vpmu_initialise(v, opt_vpmu_enabled);
break;
default:
- printk("VPMU: Initialization failed. "
- "Unknown CPU vendor %d\n", vendor);
- opt_vpmu_enabled = 0;
- break;
+ if ( opt_vpmu_enabled )
+ {
+ printk(XENLOG_G_WARNING "VPMU: Unknown CPU vendor %d. "
+ "Disabling VPMU\n", vendor);
+ opt_vpmu_enabled = 0;
+ }
+ return;
}
+
+ if ( ret )
+ printk(XENLOG_G_WARNING "VPMU: Initialization failed for %pv\n", v);
}
static void vpmu_clear_last(void *arg)
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 03/23] x86/VPMU: Manage VPMU_CONTEXT_SAVE flag in vpmu_save_force()
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 01/23] common/symbols: Export hypervisor symbols to privileged guest Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 02/23] x86/VPMU: Don't globally disable VPMU if initialization fails Boris Ostrovsky
@ 2015-01-05 21:43 ` Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 04/23] x86/VPMU: Set MSR bitmaps only for HVM/PVH guests Boris Ostrovsky
` (20 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:43 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
There is a possibility that we set VPMU_CONTEXT_SAVE on VPMU context in
vpmu_load() and never clear it (because vpmu_save_force() will see
VPMU_CONTEXT_LOADED bit clear, which is possible on AMD processors)
The problem is that amd_vpmu_save() assumes that if VPMU_CONTEXT_SAVE is set
then (1) we need to save counters and (2) we don't need to "stop" control
registers since they must have been stopped earlier. The latter may cause all
sorts of problem (like counters still running in a wrong guest and hypervisor
sending to that guest unexpected PMU interrupts).
Since setting this flag is currently always done prior to calling
vpmu_save_force() let's both set and clear it there.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/vpmu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index efb2279..e17e194 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -128,6 +128,8 @@ static void vpmu_save_force(void *arg)
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
return;
+ vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
+
if ( vpmu->arch_vpmu_ops )
(void)vpmu->arch_vpmu_ops->arch_vpmu_save(v);
@@ -176,7 +178,6 @@ void vpmu_load(struct vcpu *v)
*/
if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
{
- vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
on_selected_cpus(cpumask_of(vpmu->last_pcpu),
vpmu_save_force, (void *)v, 1);
vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
@@ -193,7 +194,6 @@ void vpmu_load(struct vcpu *v)
vpmu = vcpu_vpmu(prev);
/* Someone ran here before us */
- vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
vpmu_save_force(prev);
vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 04/23] x86/VPMU: Set MSR bitmaps only for HVM/PVH guests
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (2 preceding siblings ...)
2015-01-05 21:43 ` [PATCH v17 03/23] x86/VPMU: Manage VPMU_CONTEXT_SAVE flag in vpmu_save_force() Boris Ostrovsky
@ 2015-01-05 21:43 ` Boris Ostrovsky
2015-01-05 21:43 ` [PATCH v17 05/23] x86/VPMU: Make vpmu macros a bit more efficient Boris Ostrovsky
` (19 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:43 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
In preparation for making VPMU code shared with PV make sure that we we update
MSR bitmaps only for HVM/PVH guests
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/svm/vpmu.c | 21 +++++++++++++--------
xen/arch/x86/hvm/vmx/vpmu_core2.c | 8 +++++---
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 4c448bb..19777e3 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -244,7 +244,8 @@ static int amd_vpmu_save(struct vcpu *v)
context_save(v);
- if ( !vpmu_is_set(vpmu, VPMU_RUNNING) && ctx->msr_bitmap_set )
+ if ( !vpmu_is_set(vpmu, VPMU_RUNNING) &&
+ has_hvm_container_vcpu(v) && ctx->msr_bitmap_set )
amd_vpmu_unset_msr_bitmap(v);
return 1;
@@ -287,8 +288,9 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
ASSERT(!supported);
/* For all counters, enable guest only mode for HVM guest */
- if ( (get_pmu_reg_type(msr) == MSR_TYPE_CTRL) &&
- !(is_guest_mode(msr_content)) )
+ if ( has_hvm_container_vcpu(v) &&
+ (get_pmu_reg_type(msr) == MSR_TYPE_CTRL) &&
+ !is_guest_mode(msr_content) )
{
set_guest_mode(msr_content);
}
@@ -303,8 +305,9 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
apic_write(APIC_LVTPC, PMU_APIC_VECTOR);
vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR;
- if ( !((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
- amd_vpmu_set_msr_bitmap(v);
+ if ( has_hvm_container_vcpu(v) &&
+ !((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
+ amd_vpmu_set_msr_bitmap(v);
}
/* stop saving & restore if guest stops first counter */
@@ -314,8 +317,9 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
vpmu_reset(vpmu, VPMU_RUNNING);
- if ( ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
- amd_vpmu_unset_msr_bitmap(v);
+ if ( has_hvm_container_vcpu(v) &&
+ ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
+ amd_vpmu_unset_msr_bitmap(v);
release_pmu_ownship(PMU_OWNER_HVM);
}
@@ -403,7 +407,8 @@ static void amd_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- if ( ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
+ if ( has_hvm_container_vcpu(v) &&
+ ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
amd_vpmu_unset_msr_bitmap(v);
xfree(vpmu->context);
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 590c2a9..c9fb202 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -335,7 +335,8 @@ static int core2_vpmu_save(struct vcpu *v)
__core2_vpmu_save(v);
/* Unset PMU MSR bitmap to trap lazy load. */
- if ( !vpmu_is_set(vpmu, VPMU_RUNNING) && cpu_has_vmx_msr_bitmap )
+ if ( !vpmu_is_set(vpmu, VPMU_RUNNING) &&
+ has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
return 1;
@@ -448,7 +449,8 @@ static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
{
__core2_vpmu_load(current);
vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
- if ( cpu_has_vmx_msr_bitmap )
+ if ( has_hvm_container_vcpu(current) &&
+ cpu_has_vmx_msr_bitmap )
core2_vpmu_set_msr_bitmap(current->arch.hvm_vmx.msr_bitmap);
}
return 1;
@@ -820,7 +822,7 @@ static void core2_vpmu_destroy(struct vcpu *v)
xfree(core2_vpmu_cxt->pmu_enable);
xfree(vpmu->context);
- if ( cpu_has_vmx_msr_bitmap )
+ if ( has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
release_pmu_ownship(PMU_OWNER_HVM);
vpmu_reset(vpmu, VPMU_CONTEXT_ALLOCATED);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 05/23] x86/VPMU: Make vpmu macros a bit more efficient
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (3 preceding siblings ...)
2015-01-05 21:43 ` [PATCH v17 04/23] x86/VPMU: Set MSR bitmaps only for HVM/PVH guests Boris Ostrovsky
@ 2015-01-05 21:43 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 06/23] intel/VPMU: Clean up Intel VPMU code Boris Ostrovsky
` (18 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:43 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Introduce vpmu_are_all_set that allows testing multiple bits at once. Convert macros
into inlines for better compiler checking.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/vmx/vpmu_core2.c | 5 +----
xen/arch/x86/hvm/vpmu.c | 3 +--
xen/include/asm-x86/hvm/vpmu.h | 25 +++++++++++++++++++++----
3 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index c9fb202..951aece 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -326,10 +326,7 @@ static int core2_vpmu_save(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_SAVE) )
- return 0;
-
- if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
+ if ( !vpmu_are_all_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED) )
return 0;
__core2_vpmu_save(v);
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index e17e194..63b2158 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -143,8 +143,7 @@ void vpmu_save(struct vcpu *v)
struct vpmu_struct *vpmu = vcpu_vpmu(v);
int pcpu = smp_processor_id();
- if ( !(vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) &&
- vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED)) )
+ if ( !vpmu_are_all_set(vpmu, VPMU_CONTEXT_ALLOCATED | VPMU_CONTEXT_LOADED) )
return;
vpmu->last_pcpu = pcpu;
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 1f28bd8..ddc2748 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -82,10 +82,27 @@ struct vpmu_struct {
#define VPMU_CPU_HAS_BTS 0x200 /* Has Branch Trace Store */
-#define vpmu_set(_vpmu, _x) ((_vpmu)->flags |= (_x))
-#define vpmu_reset(_vpmu, _x) ((_vpmu)->flags &= ~(_x))
-#define vpmu_is_set(_vpmu, _x) ((_vpmu)->flags & (_x))
-#define vpmu_clear(_vpmu) ((_vpmu)->flags = 0)
+static inline void vpmu_set(struct vpmu_struct *vpmu, const u32 mask)
+{
+ vpmu->flags |= mask;
+}
+static inline void vpmu_reset(struct vpmu_struct *vpmu, const u32 mask)
+{
+ vpmu->flags &= ~mask;
+}
+static inline void vpmu_clear(struct vpmu_struct *vpmu)
+{
+ vpmu->flags = 0;
+}
+static inline bool_t vpmu_is_set(const struct vpmu_struct *vpmu, const u32 mask)
+{
+ return !!(vpmu->flags & mask);
+}
+static inline bool_t vpmu_are_all_set(const struct vpmu_struct *vpmu,
+ const u32 mask)
+{
+ return !!((vpmu->flags & mask) == mask);
+}
int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported);
int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 06/23] intel/VPMU: Clean up Intel VPMU code
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (4 preceding siblings ...)
2015-01-05 21:43 ` [PATCH v17 05/23] x86/VPMU: Make vpmu macros a bit more efficient Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 07/23] vmx: Merge MSR management routines Boris Ostrovsky
` (17 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Remove struct pmumsr and core2_pmu_enable. Replace static MSR structures with
fields in core2_vpmu_context.
Call core2_get_pmc_count() once, during initialization.
Properly clean up when core2_vpmu_alloc_resource() fails.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/vmx/vpmu_core2.c | 380 ++++++++++++++-----------------
xen/include/asm-x86/hvm/vmx/vpmu_core2.h | 19 --
2 files changed, 171 insertions(+), 228 deletions(-)
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 951aece..9c4d00e 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -69,6 +69,27 @@
static bool_t __read_mostly full_width_write;
/*
+ * MSR_CORE_PERF_FIXED_CTR_CTRL contains the configuration of all fixed
+ * counters. 4 bits for every counter.
+ */
+#define FIXED_CTR_CTRL_BITS 4
+#define FIXED_CTR_CTRL_MASK ((1 << FIXED_CTR_CTRL_BITS) - 1)
+
+#define VPMU_CORE2_MAX_FIXED_PMCS 4
+struct core2_vpmu_context {
+ u64 fixed_ctrl;
+ u64 ds_area;
+ u64 pebs_enable;
+ u64 global_ovf_status;
+ u64 enabled_cntrs; /* Follows PERF_GLOBAL_CTRL MSR format */
+ u64 fix_counters[VPMU_CORE2_MAX_FIXED_PMCS];
+ struct arch_msr_pair arch_msr_pair[1];
+};
+
+/* Number of general-purpose and fixed performance counters */
+static unsigned int __read_mostly arch_pmc_cnt, fixed_pmc_cnt;
+
+/*
* QUIRK to workaround an issue on various family 6 cpus.
* The issue leads to endless PMC interrupt loops on the processor.
* If the interrupt handler is running and a pmc reaches the value 0, this
@@ -88,11 +109,8 @@ static void check_pmc_quirk(void)
is_pmc_quirk = 0;
}
-static int core2_get_pmc_count(void);
static void handle_pmc_quirk(u64 msr_content)
{
- int num_gen_pmc = core2_get_pmc_count();
- int num_fix_pmc = 3;
int i;
u64 val;
@@ -100,7 +118,7 @@ static void handle_pmc_quirk(u64 msr_content)
return;
val = msr_content;
- for ( i = 0; i < num_gen_pmc; i++ )
+ for ( i = 0; i < arch_pmc_cnt; i++ )
{
if ( val & 0x1 )
{
@@ -112,7 +130,7 @@ static void handle_pmc_quirk(u64 msr_content)
val >>= 1;
}
val = msr_content >> 32;
- for ( i = 0; i < num_fix_pmc; i++ )
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
{
if ( val & 0x1 )
{
@@ -125,128 +143,91 @@ static void handle_pmc_quirk(u64 msr_content)
}
}
-static const u32 core2_fix_counters_msr[] = {
- MSR_CORE_PERF_FIXED_CTR0,
- MSR_CORE_PERF_FIXED_CTR1,
- MSR_CORE_PERF_FIXED_CTR2
-};
-
/*
- * MSR_CORE_PERF_FIXED_CTR_CTRL contains the configuration of all fixed
- * counters. 4 bits for every counter.
+ * Read the number of general counters via CPUID.EAX[0xa].EAX[8..15]
*/
-#define FIXED_CTR_CTRL_BITS 4
-#define FIXED_CTR_CTRL_MASK ((1 << FIXED_CTR_CTRL_BITS) - 1)
-
-/* The index into the core2_ctrls_msr[] of this MSR used in core2_vpmu_dump() */
-#define MSR_CORE_PERF_FIXED_CTR_CTRL_IDX 0
-
-/* Core 2 Non-architectual Performance Control MSRs. */
-static const u32 core2_ctrls_msr[] = {
- MSR_CORE_PERF_FIXED_CTR_CTRL,
- MSR_IA32_PEBS_ENABLE,
- MSR_IA32_DS_AREA
-};
-
-struct pmumsr {
- unsigned int num;
- const u32 *msr;
-};
-
-static const struct pmumsr core2_fix_counters = {
- VPMU_CORE2_NUM_FIXED,
- core2_fix_counters_msr
-};
+static int core2_get_arch_pmc_count(void)
+{
+ u32 eax;
-static const struct pmumsr core2_ctrls = {
- VPMU_CORE2_NUM_CTRLS,
- core2_ctrls_msr
-};
-static int arch_pmc_cnt;
+ eax = cpuid_eax(0xa);
+ return MASK_EXTR(eax, PMU_GENERAL_NR_MASK);
+}
/*
- * Read the number of general counters via CPUID.EAX[0xa].EAX[8..15]
+ * Read the number of fixed counters via CPUID.EDX[0xa].EDX[0..4]
*/
-static int core2_get_pmc_count(void)
+static int core2_get_fixed_pmc_count(void)
{
- u32 eax, ebx, ecx, edx;
+ u32 eax;
- if ( arch_pmc_cnt == 0 )
- {
- cpuid(0xa, &eax, &ebx, &ecx, &edx);
- arch_pmc_cnt = (eax & PMU_GENERAL_NR_MASK) >> PMU_GENERAL_NR_SHIFT;
- }
-
- return arch_pmc_cnt;
+ eax = cpuid_eax(0xa);
+ return MASK_EXTR(eax, PMU_FIXED_NR_MASK);
}
static u64 core2_calc_intial_glb_ctrl_msr(void)
{
- int arch_pmc_bits = (1 << core2_get_pmc_count()) - 1;
- u64 fix_pmc_bits = (1 << 3) - 1;
- return ((fix_pmc_bits << 32) | arch_pmc_bits);
+ int arch_pmc_bits = (1 << arch_pmc_cnt) - 1;
+ u64 fix_pmc_bits = (1 << fixed_pmc_cnt) - 1;
+
+ return (fix_pmc_bits << 32) | arch_pmc_bits;
}
/* edx bits 5-12: Bit width of fixed-function performance counters */
static int core2_get_bitwidth_fix_count(void)
{
- u32 eax, ebx, ecx, edx;
+ u32 edx;
- cpuid(0xa, &eax, &ebx, &ecx, &edx);
- return ((edx & PMU_FIXED_WIDTH_MASK) >> PMU_FIXED_WIDTH_SHIFT);
+ edx = cpuid_edx(0xa);
+ return MASK_EXTR(edx, PMU_FIXED_WIDTH_MASK);
}
static int is_core2_vpmu_msr(u32 msr_index, int *type, int *index)
{
- int i;
u32 msr_index_pmc;
- for ( i = 0; i < core2_fix_counters.num; i++ )
+ switch ( msr_index )
{
- if ( core2_fix_counters.msr[i] == msr_index )
+ case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ case MSR_IA32_DS_AREA:
+ case MSR_IA32_PEBS_ENABLE:
+ *type = MSR_TYPE_CTRL;
+ return 1;
+
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ *type = MSR_TYPE_GLOBAL;
+ return 1;
+
+ default:
+
+ if ( (msr_index >= MSR_CORE_PERF_FIXED_CTR0) &&
+ (msr_index < MSR_CORE_PERF_FIXED_CTR0 + fixed_pmc_cnt) )
{
+ *index = msr_index - MSR_CORE_PERF_FIXED_CTR0;
*type = MSR_TYPE_COUNTER;
- *index = i;
return 1;
}
- }
- for ( i = 0; i < core2_ctrls.num; i++ )
- {
- if ( core2_ctrls.msr[i] == msr_index )
+ if ( (msr_index >= MSR_P6_EVNTSEL(0)) &&
+ (msr_index < MSR_P6_EVNTSEL(arch_pmc_cnt)) )
{
- *type = MSR_TYPE_CTRL;
- *index = i;
+ *index = msr_index - MSR_P6_EVNTSEL(0);
+ *type = MSR_TYPE_ARCH_CTRL;
return 1;
}
- }
- if ( (msr_index == MSR_CORE_PERF_GLOBAL_CTRL) ||
- (msr_index == MSR_CORE_PERF_GLOBAL_STATUS) ||
- (msr_index == MSR_CORE_PERF_GLOBAL_OVF_CTRL) )
- {
- *type = MSR_TYPE_GLOBAL;
- return 1;
- }
-
- msr_index_pmc = msr_index & MSR_PMC_ALIAS_MASK;
- if ( (msr_index_pmc >= MSR_IA32_PERFCTR0) &&
- (msr_index_pmc < (MSR_IA32_PERFCTR0 + core2_get_pmc_count())) )
- {
- *type = MSR_TYPE_ARCH_COUNTER;
- *index = msr_index_pmc - MSR_IA32_PERFCTR0;
- return 1;
- }
-
- if ( (msr_index >= MSR_P6_EVNTSEL(0)) &&
- (msr_index < (MSR_P6_EVNTSEL(core2_get_pmc_count()))) )
- {
- *type = MSR_TYPE_ARCH_CTRL;
- *index = msr_index - MSR_P6_EVNTSEL(0);
- return 1;
+ msr_index_pmc = msr_index & MSR_PMC_ALIAS_MASK;
+ if ( (msr_index_pmc >= MSR_IA32_PERFCTR0) &&
+ (msr_index_pmc < (MSR_IA32_PERFCTR0 + arch_pmc_cnt)) )
+ {
+ *type = MSR_TYPE_ARCH_COUNTER;
+ *index = msr_index_pmc - MSR_IA32_PERFCTR0;
+ return 1;
+ }
+ return 0;
}
-
- return 0;
}
static void core2_vpmu_set_msr_bitmap(unsigned long *msr_bitmap)
@@ -254,13 +235,13 @@ static void core2_vpmu_set_msr_bitmap(unsigned long *msr_bitmap)
int i;
/* Allow Read/Write PMU Counters MSR Directly. */
- for ( i = 0; i < core2_fix_counters.num; i++ )
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
{
- clear_bit(msraddr_to_bitpos(core2_fix_counters.msr[i]), msr_bitmap);
- clear_bit(msraddr_to_bitpos(core2_fix_counters.msr[i]),
+ clear_bit(msraddr_to_bitpos(MSR_CORE_PERF_FIXED_CTR0 + i), msr_bitmap);
+ clear_bit(msraddr_to_bitpos(MSR_CORE_PERF_FIXED_CTR0 + i),
msr_bitmap + 0x800/BYTES_PER_LONG);
}
- for ( i = 0; i < core2_get_pmc_count(); i++ )
+ for ( i = 0; i < arch_pmc_cnt; i++ )
{
clear_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i), msr_bitmap);
clear_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i),
@@ -275,26 +256,28 @@ static void core2_vpmu_set_msr_bitmap(unsigned long *msr_bitmap)
}
/* Allow Read PMU Non-global Controls Directly. */
- for ( i = 0; i < core2_ctrls.num; i++ )
- clear_bit(msraddr_to_bitpos(core2_ctrls.msr[i]), msr_bitmap);
- for ( i = 0; i < core2_get_pmc_count(); i++ )
- clear_bit(msraddr_to_bitpos(MSR_P6_EVNTSEL(i)), msr_bitmap);
+ for ( i = 0; i < arch_pmc_cnt; i++ )
+ clear_bit(msraddr_to_bitpos(MSR_P6_EVNTSEL(i)), msr_bitmap);
+
+ clear_bit(msraddr_to_bitpos(MSR_CORE_PERF_FIXED_CTR_CTRL), msr_bitmap);
+ clear_bit(msraddr_to_bitpos(MSR_IA32_PEBS_ENABLE), msr_bitmap);
+ clear_bit(msraddr_to_bitpos(MSR_IA32_DS_AREA), msr_bitmap);
}
static void core2_vpmu_unset_msr_bitmap(unsigned long *msr_bitmap)
{
int i;
- for ( i = 0; i < core2_fix_counters.num; i++ )
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
{
- set_bit(msraddr_to_bitpos(core2_fix_counters.msr[i]), msr_bitmap);
- set_bit(msraddr_to_bitpos(core2_fix_counters.msr[i]),
+ set_bit(msraddr_to_bitpos(MSR_CORE_PERF_FIXED_CTR0 + i), msr_bitmap);
+ set_bit(msraddr_to_bitpos(MSR_CORE_PERF_FIXED_CTR0 + i),
msr_bitmap + 0x800/BYTES_PER_LONG);
}
- for ( i = 0; i < core2_get_pmc_count(); i++ )
+ for ( i = 0; i < arch_pmc_cnt; i++ )
{
- set_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i), msr_bitmap);
- set_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i),
+ set_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0 + i), msr_bitmap);
+ set_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0 + i),
msr_bitmap + 0x800/BYTES_PER_LONG);
if ( full_width_write )
@@ -305,10 +288,12 @@ static void core2_vpmu_unset_msr_bitmap(unsigned long *msr_bitmap)
}
}
- for ( i = 0; i < core2_ctrls.num; i++ )
- set_bit(msraddr_to_bitpos(core2_ctrls.msr[i]), msr_bitmap);
- for ( i = 0; i < core2_get_pmc_count(); i++ )
+ for ( i = 0; i < arch_pmc_cnt; i++ )
set_bit(msraddr_to_bitpos(MSR_P6_EVNTSEL(i)), msr_bitmap);
+
+ set_bit(msraddr_to_bitpos(MSR_CORE_PERF_FIXED_CTR_CTRL), msr_bitmap);
+ set_bit(msraddr_to_bitpos(MSR_IA32_PEBS_ENABLE), msr_bitmap);
+ set_bit(msraddr_to_bitpos(MSR_IA32_DS_AREA), msr_bitmap);
}
static inline void __core2_vpmu_save(struct vcpu *v)
@@ -316,10 +301,10 @@ static inline void __core2_vpmu_save(struct vcpu *v)
int i;
struct core2_vpmu_context *core2_vpmu_cxt = vcpu_vpmu(v)->context;
- for ( i = 0; i < core2_fix_counters.num; i++ )
- rdmsrl(core2_fix_counters.msr[i], core2_vpmu_cxt->fix_counters[i]);
- for ( i = 0; i < core2_get_pmc_count(); i++ )
- rdmsrl(MSR_IA32_PERFCTR0+i, core2_vpmu_cxt->arch_msr_pair[i].counter);
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
+ rdmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, core2_vpmu_cxt->fix_counters[i]);
+ for ( i = 0; i < arch_pmc_cnt; i++ )
+ rdmsrl(MSR_IA32_PERFCTR0 + i, core2_vpmu_cxt->arch_msr_pair[i].counter);
}
static int core2_vpmu_save(struct vcpu *v)
@@ -344,20 +329,22 @@ static inline void __core2_vpmu_load(struct vcpu *v)
unsigned int i, pmc_start;
struct core2_vpmu_context *core2_vpmu_cxt = vcpu_vpmu(v)->context;
- for ( i = 0; i < core2_fix_counters.num; i++ )
- wrmsrl(core2_fix_counters.msr[i], core2_vpmu_cxt->fix_counters[i]);
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
+ wrmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, core2_vpmu_cxt->fix_counters[i]);
if ( full_width_write )
pmc_start = MSR_IA32_A_PERFCTR0;
else
pmc_start = MSR_IA32_PERFCTR0;
- for ( i = 0; i < core2_get_pmc_count(); i++ )
+ for ( i = 0; i < arch_pmc_cnt; i++ )
+ {
wrmsrl(pmc_start + i, core2_vpmu_cxt->arch_msr_pair[i].counter);
-
- for ( i = 0; i < core2_ctrls.num; i++ )
- wrmsrl(core2_ctrls.msr[i], core2_vpmu_cxt->ctrls[i]);
- for ( i = 0; i < core2_get_pmc_count(); i++ )
wrmsrl(MSR_P6_EVNTSEL(i), core2_vpmu_cxt->arch_msr_pair[i].control);
+ }
+
+ wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, core2_vpmu_cxt->fixed_ctrl);
+ wrmsrl(MSR_IA32_DS_AREA, core2_vpmu_cxt->ds_area);
+ wrmsrl(MSR_IA32_PEBS_ENABLE, core2_vpmu_cxt->pebs_enable);
}
static void core2_vpmu_load(struct vcpu *v)
@@ -376,56 +363,37 @@ static int core2_vpmu_alloc_resource(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
struct core2_vpmu_context *core2_vpmu_cxt;
- struct core2_pmu_enable *pmu_enable;
if ( !acquire_pmu_ownership(PMU_OWNER_HVM) )
return 0;
wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
if ( vmx_add_host_load_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
- return 0;
+ goto out_err;
if ( vmx_add_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
- return 0;
+ goto out_err;
vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL,
core2_calc_intial_glb_ctrl_msr());
- pmu_enable = xzalloc_bytes(sizeof(struct core2_pmu_enable) +
- core2_get_pmc_count() - 1);
- if ( !pmu_enable )
- goto out1;
-
core2_vpmu_cxt = xzalloc_bytes(sizeof(struct core2_vpmu_context) +
- (core2_get_pmc_count()-1)*sizeof(struct arch_msr_pair));
+ (arch_pmc_cnt-1)*sizeof(struct arch_msr_pair));
if ( !core2_vpmu_cxt )
- goto out2;
- core2_vpmu_cxt->pmu_enable = pmu_enable;
+ goto out_err;
+
vpmu->context = (void *)core2_vpmu_cxt;
+ vpmu_set(vpmu, VPMU_CONTEXT_ALLOCATED);
+
return 1;
- out2:
- xfree(pmu_enable);
- out1:
- gdprintk(XENLOG_WARNING, "Insufficient memory for PMU, PMU feature is "
- "unavailable on domain %d vcpu %d.\n",
- v->vcpu_id, v->domain->domain_id);
- return 0;
-}
-static void core2_vpmu_save_msr_context(struct vcpu *v, int type,
- int index, u64 msr_data)
-{
- struct core2_vpmu_context *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+out_err:
+ release_pmu_ownship(PMU_OWNER_HVM);
- switch ( type )
- {
- case MSR_TYPE_CTRL:
- core2_vpmu_cxt->ctrls[index] = msr_data;
- break;
- case MSR_TYPE_ARCH_CTRL:
- core2_vpmu_cxt->arch_msr_pair[index].control = msr_data;
- break;
- }
+ printk("Failed to allocate VPMU resources for domain %u vcpu %u\n",
+ v->vcpu_id, v->domain->domain_id);
+
+ return 0;
}
static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
@@ -436,10 +404,8 @@ static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
return 0;
if ( unlikely(!vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED)) &&
- (vpmu->context != NULL ||
- !core2_vpmu_alloc_resource(current)) )
+ !core2_vpmu_alloc_resource(current) )
return 0;
- vpmu_set(vpmu, VPMU_CONTEXT_ALLOCATED);
/* Do the lazy load staff. */
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
@@ -456,8 +422,7 @@ static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
uint64_t supported)
{
- u64 global_ctrl, non_global_ctrl;
- char pmu_enable = 0;
+ u64 global_ctrl;
int i, tmp;
int type = -1, index = -1;
struct vcpu *v = current;
@@ -504,6 +469,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( msr_content & 1 )
gdprintk(XENLOG_WARNING, "Guest is trying to enable PEBS, "
"which is not supported.\n");
+ core2_vpmu_cxt->pebs_enable = msr_content;
return 1;
case MSR_IA32_DS_AREA:
if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_DS) )
@@ -516,57 +482,48 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
hvm_inject_hw_exception(TRAP_gp_fault, 0);
return 1;
}
- core2_vpmu_cxt->pmu_enable->ds_area_enable = msr_content ? 1 : 0;
+ core2_vpmu_cxt->ds_area = msr_content;
break;
}
gdprintk(XENLOG_WARNING, "Guest setting of DTS is ignored.\n");
return 1;
case MSR_CORE_PERF_GLOBAL_CTRL:
global_ctrl = msr_content;
- for ( i = 0; i < core2_get_pmc_count(); i++ )
- {
- rdmsrl(MSR_P6_EVNTSEL(i), non_global_ctrl);
- core2_vpmu_cxt->pmu_enable->arch_pmc_enable[i] =
- global_ctrl & (non_global_ctrl >> 22) & 1;
- global_ctrl >>= 1;
- }
-
- rdmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, non_global_ctrl);
- global_ctrl = msr_content >> 32;
- for ( i = 0; i < core2_fix_counters.num; i++ )
- {
- core2_vpmu_cxt->pmu_enable->fixed_ctr_enable[i] =
- (global_ctrl & 1) & ((non_global_ctrl & 0x3)? 1: 0);
- non_global_ctrl >>= FIXED_CTR_CTRL_BITS;
- global_ctrl >>= 1;
- }
break;
case MSR_CORE_PERF_FIXED_CTR_CTRL:
- non_global_ctrl = msr_content;
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
- global_ctrl >>= 32;
- for ( i = 0; i < core2_fix_counters.num; i++ )
+ core2_vpmu_cxt->enabled_cntrs &=
+ ~(((1ULL << VPMU_CORE2_MAX_FIXED_PMCS) - 1) << 32);
+ if ( msr_content != 0 )
{
- core2_vpmu_cxt->pmu_enable->fixed_ctr_enable[i] =
- (global_ctrl & 1) & ((non_global_ctrl & 0x3)? 1: 0);
- non_global_ctrl >>= 4;
- global_ctrl >>= 1;
+ u64 val = msr_content;
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
+ {
+ if ( val & 3 )
+ core2_vpmu_cxt->enabled_cntrs |= (1ULL << 32) << i;
+ val >>= FIXED_CTR_CTRL_BITS;
+ }
}
+
+ core2_vpmu_cxt->fixed_ctrl = msr_content;
break;
default:
tmp = msr - MSR_P6_EVNTSEL(0);
- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
- if ( tmp >= 0 && tmp < core2_get_pmc_count() )
- core2_vpmu_cxt->pmu_enable->arch_pmc_enable[tmp] =
- (global_ctrl >> tmp) & (msr_content >> 22) & 1;
+ if ( tmp >= 0 && tmp < arch_pmc_cnt )
+ {
+ vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
+
+ if ( msr_content & (1ULL << 22) )
+ core2_vpmu_cxt->enabled_cntrs |= 1ULL << tmp;
+ else
+ core2_vpmu_cxt->enabled_cntrs &= ~(1ULL << tmp);
+
+ core2_vpmu_cxt->arch_msr_pair[tmp].control = msr_content;
+ }
}
- for ( i = 0; i < core2_fix_counters.num; i++ )
- pmu_enable |= core2_vpmu_cxt->pmu_enable->fixed_ctr_enable[i];
- for ( i = 0; i < core2_get_pmc_count(); i++ )
- pmu_enable |= core2_vpmu_cxt->pmu_enable->arch_pmc_enable[i];
- pmu_enable |= core2_vpmu_cxt->pmu_enable->ds_area_enable;
- if ( pmu_enable )
+ if ( (global_ctrl & core2_vpmu_cxt->enabled_cntrs) ||
+ (core2_vpmu_cxt->ds_area != 0) )
vpmu_set(vpmu, VPMU_RUNNING);
else
vpmu_reset(vpmu, VPMU_RUNNING);
@@ -584,7 +541,6 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
}
- core2_vpmu_save_msr_context(v, type, index, msr_content);
if ( type != MSR_TYPE_GLOBAL )
{
u64 mask;
@@ -600,7 +556,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( msr == MSR_IA32_DS_AREA )
break;
/* 4 bits per counter, currently 3 fixed counters implemented. */
- mask = ~((1ull << (VPMU_CORE2_NUM_FIXED * FIXED_CTR_CTRL_BITS)) - 1);
+ mask = ~((1ull << (fixed_pmc_cnt * FIXED_CTR_CTRL_BITS)) - 1);
if (msr_content & mask)
inject_gp = 1;
break;
@@ -685,7 +641,7 @@ static void core2_vpmu_do_cpuid(unsigned int input,
static void core2_vpmu_dump(const struct vcpu *v)
{
const struct vpmu_struct *vpmu = vcpu_vpmu(v);
- int i, num;
+ unsigned int i;
const struct core2_vpmu_context *core2_vpmu_cxt = NULL;
u64 val;
@@ -703,27 +659,25 @@ static void core2_vpmu_dump(const struct vcpu *v)
printk(" vPMU running\n");
core2_vpmu_cxt = vpmu->context;
- num = core2_get_pmc_count();
+
/* Print the contents of the counter and its configuration msr. */
- for ( i = 0; i < num; i++ )
+ for ( i = 0; i < arch_pmc_cnt; i++ )
{
const struct arch_msr_pair *msr_pair = core2_vpmu_cxt->arch_msr_pair;
- if ( core2_vpmu_cxt->pmu_enable->arch_pmc_enable[i] )
- printk(" general_%d: 0x%016lx ctrl: 0x%016lx\n",
- i, msr_pair[i].counter, msr_pair[i].control);
+ printk(" general_%d: 0x%016lx ctrl: 0x%016lx\n",
+ i, msr_pair[i].counter, msr_pair[i].control);
}
/*
* The configuration of the fixed counter is 4 bits each in the
* MSR_CORE_PERF_FIXED_CTR_CTRL.
*/
- val = core2_vpmu_cxt->ctrls[MSR_CORE_PERF_FIXED_CTR_CTRL_IDX];
- for ( i = 0; i < core2_fix_counters.num; i++ )
+ val = core2_vpmu_cxt->fixed_ctrl;
+ for ( i = 0; i < fixed_pmc_cnt; i++ )
{
- if ( core2_vpmu_cxt->pmu_enable->fixed_ctr_enable[i] )
- printk(" fixed_%d: 0x%016lx ctrl: %#lx\n",
- i, core2_vpmu_cxt->fix_counters[i],
- val & FIXED_CTR_CTRL_MASK);
+ printk(" fixed_%d: 0x%016lx ctrl: %#lx\n",
+ i, core2_vpmu_cxt->fix_counters[i],
+ val & FIXED_CTR_CTRL_MASK);
val >>= FIXED_CTR_CTRL_BITS;
}
}
@@ -741,7 +695,7 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
if ( is_pmc_quirk )
handle_pmc_quirk(msr_content);
core2_vpmu_cxt->global_ovf_status |= msr_content;
- msr_content = 0xC000000700000000 | ((1 << core2_get_pmc_count()) - 1);
+ msr_content = 0xC000000700000000 | ((1 << arch_pmc_cnt) - 1);
wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, msr_content);
}
else
@@ -808,6 +762,16 @@ static int core2_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
}
ds_warned = 1;
func_out:
+
+ arch_pmc_cnt = core2_get_arch_pmc_count();
+ fixed_pmc_cnt = core2_get_fixed_pmc_count();
+ if ( fixed_pmc_cnt > VPMU_CORE2_MAX_FIXED_PMCS )
+ {
+ fixed_pmc_cnt = VPMU_CORE2_MAX_FIXED_PMCS;
+ printk(XENLOG_G_WARNING "Limiting number of fixed counters to %d\n",
+ fixed_pmc_cnt);
+ }
+
check_pmc_quirk();
return 0;
}
@@ -815,9 +779,7 @@ static int core2_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
static void core2_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct core2_vpmu_context *core2_vpmu_cxt = vpmu->context;
- xfree(core2_vpmu_cxt->pmu_enable);
xfree(vpmu->context);
if ( has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
diff --git a/xen/include/asm-x86/hvm/vmx/vpmu_core2.h b/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
index 60b05fd..410372d 100644
--- a/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
+++ b/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
@@ -23,29 +23,10 @@
#ifndef __ASM_X86_HVM_VPMU_CORE_H_
#define __ASM_X86_HVM_VPMU_CORE_H_
-/* Currently only 3 fixed counters are supported. */
-#define VPMU_CORE2_NUM_FIXED 3
-/* Currently only 3 Non-architectual Performance Control MSRs */
-#define VPMU_CORE2_NUM_CTRLS 3
-
struct arch_msr_pair {
u64 counter;
u64 control;
};
-struct core2_pmu_enable {
- char ds_area_enable;
- char fixed_ctr_enable[VPMU_CORE2_NUM_FIXED];
- char arch_pmc_enable[1];
-};
-
-struct core2_vpmu_context {
- struct core2_pmu_enable *pmu_enable;
- u64 fix_counters[VPMU_CORE2_NUM_FIXED];
- u64 ctrls[VPMU_CORE2_NUM_CTRLS];
- u64 global_ovf_status;
- struct arch_msr_pair arch_msr_pair[1];
-};
-
#endif /* __ASM_X86_HVM_VPMU_CORE_H_ */
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 07/23] vmx: Merge MSR management routines
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (5 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 06/23] intel/VPMU: Clean up Intel VPMU code Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 08/23] x86/VPMU: Handle APIC_LVTPC accesses Boris Ostrovsky
` (16 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
vmx_add_host_load_msr() and vmx_add_guest_msr() share fair amount of code. Merge
them to simplify code maintenance.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/vmx/vmcs.c | 84 +++++++++++++++++++-------------------
xen/include/asm-x86/hvm/vmx/vmcs.h | 16 +++++++-
2 files changed, 55 insertions(+), 45 deletions(-)
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 9d8033e..b9e3ef8 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1201,64 +1201,62 @@ int vmx_write_guest_msr(u32 msr, u64 val)
return -ESRCH;
}
-int vmx_add_guest_msr(u32 msr)
+int vmx_add_msr(u32 msr, int type)
{
struct vcpu *curr = current;
- unsigned int i, msr_count = curr->arch.hvm_vmx.msr_count;
- struct vmx_msr_entry *msr_area = curr->arch.hvm_vmx.msr_area;
+ unsigned int idx, *msr_count;
+ struct vmx_msr_entry **msr_area, *msr_area_elem;
+
+ if ( type == VMX_GUEST_MSR )
+ {
+ msr_count = &curr->arch.hvm_vmx.msr_count;
+ msr_area = &curr->arch.hvm_vmx.msr_area;
+ }
+ else
+ {
+ ASSERT(type == VMX_HOST_MSR);
+ msr_count = &curr->arch.hvm_vmx.host_msr_count;
+ msr_area = &curr->arch.hvm_vmx.host_msr_area;
+ }
- if ( msr_area == NULL )
+ if ( *msr_area == NULL )
{
- if ( (msr_area = alloc_xenheap_page()) == NULL )
+ if ( (*msr_area = alloc_xenheap_page()) == NULL )
return -ENOMEM;
- curr->arch.hvm_vmx.msr_area = msr_area;
- __vmwrite(VM_EXIT_MSR_STORE_ADDR, virt_to_maddr(msr_area));
- __vmwrite(VM_ENTRY_MSR_LOAD_ADDR, virt_to_maddr(msr_area));
+
+ if ( type == VMX_GUEST_MSR )
+ {
+ __vmwrite(VM_EXIT_MSR_STORE_ADDR, virt_to_maddr(*msr_area));
+ __vmwrite(VM_ENTRY_MSR_LOAD_ADDR, virt_to_maddr(*msr_area));
+ }
+ else
+ __vmwrite(VM_EXIT_MSR_LOAD_ADDR, virt_to_maddr(*msr_area));
}
- for ( i = 0; i < msr_count; i++ )
- if ( msr_area[i].index == msr )
+ for ( idx = 0; idx < *msr_count; idx++ )
+ if ( (*msr_area)[idx].index == msr )
return 0;
- if ( msr_count == (PAGE_SIZE / sizeof(struct vmx_msr_entry)) )
+ if ( *msr_count == (PAGE_SIZE / sizeof(struct vmx_msr_entry)) )
return -ENOSPC;
- msr_area[msr_count].index = msr;
- msr_area[msr_count].mbz = 0;
- msr_area[msr_count].data = 0;
- curr->arch.hvm_vmx.msr_count = ++msr_count;
- __vmwrite(VM_EXIT_MSR_STORE_COUNT, msr_count);
- __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, msr_count);
+ msr_area_elem = *msr_area + *msr_count;
+ msr_area_elem->index = msr;
+ msr_area_elem->mbz = 0;
- return 0;
-}
+ ++*msr_count;
-int vmx_add_host_load_msr(u32 msr)
-{
- struct vcpu *curr = current;
- unsigned int i, msr_count = curr->arch.hvm_vmx.host_msr_count;
- struct vmx_msr_entry *msr_area = curr->arch.hvm_vmx.host_msr_area;
-
- if ( msr_area == NULL )
+ if ( type == VMX_GUEST_MSR )
{
- if ( (msr_area = alloc_xenheap_page()) == NULL )
- return -ENOMEM;
- curr->arch.hvm_vmx.host_msr_area = msr_area;
- __vmwrite(VM_EXIT_MSR_LOAD_ADDR, virt_to_maddr(msr_area));
+ msr_area_elem->data = 0;
+ __vmwrite(VM_EXIT_MSR_STORE_COUNT, *msr_count);
+ __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, *msr_count);
+ }
+ else
+ {
+ rdmsrl(msr, msr_area_elem->data);
+ __vmwrite(VM_EXIT_MSR_LOAD_COUNT, *msr_count);
}
-
- for ( i = 0; i < msr_count; i++ )
- if ( msr_area[i].index == msr )
- return 0;
-
- if ( msr_count == (PAGE_SIZE / sizeof(struct vmx_msr_entry)) )
- return -ENOSPC;
-
- msr_area[msr_count].index = msr;
- msr_area[msr_count].mbz = 0;
- rdmsrl(msr, msr_area[msr_count].data);
- curr->arch.hvm_vmx.host_msr_count = ++msr_count;
- __vmwrite(VM_EXIT_MSR_LOAD_COUNT, msr_count);
return 0;
}
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 6a99dca..949884b 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -482,12 +482,15 @@ extern const unsigned int vmx_introspection_force_enabled_msrs_size;
#define MSR_TYPE_R 1
#define MSR_TYPE_W 2
+
+#define VMX_GUEST_MSR 0
+#define VMX_HOST_MSR 1
+
void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type);
void vmx_enable_intercept_for_msr(struct vcpu *v, u32 msr, int type);
int vmx_read_guest_msr(u32 msr, u64 *val);
int vmx_write_guest_msr(u32 msr, u64 val);
-int vmx_add_guest_msr(u32 msr);
-int vmx_add_host_load_msr(u32 msr);
+int vmx_add_msr(u32 msr, int type);
void vmx_vmcs_switch(struct vmcs_struct *from, struct vmcs_struct *to);
void vmx_set_eoi_exit_bitmap(struct vcpu *v, u8 vector);
void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector);
@@ -497,6 +500,15 @@ void virtual_vmcs_exit(void *vvmcs);
u64 virtual_vmcs_vmread(void *vvmcs, u32 vmcs_encoding);
void virtual_vmcs_vmwrite(void *vvmcs, u32 vmcs_encoding, u64 val);
+static inline int vmx_add_guest_msr(u32 msr)
+{
+ return vmx_add_msr(msr, VMX_GUEST_MSR);
+}
+static inline int vmx_add_host_load_msr(u32 msr)
+{
+ return vmx_add_msr(msr, VMX_HOST_MSR);
+}
+
DECLARE_PER_CPU(bool_t, vmxon);
#endif /* ASM_X86_HVM_VMX_VMCS_H__ */
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 08/23] x86/VPMU: Handle APIC_LVTPC accesses
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (6 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 07/23] vmx: Merge MSR management routines Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 09/23] intel/VPMU: MSR_CORE_PERF_GLOBAL_CTRL should be initialized to zero Boris Ostrovsky
` (15 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Don't have the hypervisor update APIC_LVTPC when _it_ thinks the vector should
be updated. Instead, handle guest's APIC_LVTPC accesses and write what the guest
explicitly wanted.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/svm/vpmu.c | 4 ----
xen/arch/x86/hvm/vlapic.c | 3 +++
xen/arch/x86/hvm/vmx/vpmu_core2.c | 17 -----------------
xen/arch/x86/hvm/vpmu.c | 8 ++++++++
xen/include/asm-x86/hvm/vpmu.h | 1 +
5 files changed, 12 insertions(+), 21 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 19777e3..64dc167 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -302,8 +302,6 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( !acquire_pmu_ownership(PMU_OWNER_HVM) )
return 1;
vpmu_set(vpmu, VPMU_RUNNING);
- apic_write(APIC_LVTPC, PMU_APIC_VECTOR);
- vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR;
if ( has_hvm_container_vcpu(v) &&
!((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
@@ -314,8 +312,6 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( (get_pmu_reg_type(msr) == MSR_TYPE_CTRL) &&
(is_pmu_enabled(msr_content) == 0) && vpmu_is_set(vpmu, VPMU_RUNNING) )
{
- apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
- vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
vpmu_reset(vpmu, VPMU_RUNNING);
if ( has_hvm_container_vcpu(v) &&
((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 72b6509..56b9d23 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -38,6 +38,7 @@
#include <asm/hvm/support.h>
#include <asm/hvm/vmx/vmx.h>
#include <asm/hvm/nestedhvm.h>
+#include <asm/hvm/vpmu.h>
#include <public/hvm/ioreq.h>
#include <public/hvm/params.h>
@@ -789,6 +790,8 @@ static int vlapic_reg_write(struct vcpu *v,
}
if ( (offset == APIC_LVTT) && !(val & APIC_LVT_MASKED) )
pt_may_unmask_irq(NULL, &vlapic->pt);
+ if ( offset == APIC_LVTPC )
+ vpmu_lvtpc_update(val);
break;
case APIC_TMICT:
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 9c4d00e..8b84079 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -528,19 +528,6 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
else
vpmu_reset(vpmu, VPMU_RUNNING);
- /* Setup LVTPC in local apic */
- if ( vpmu_is_set(vpmu, VPMU_RUNNING) &&
- is_vlapic_lvtpc_enabled(vcpu_vlapic(v)) )
- {
- apic_write_around(APIC_LVTPC, PMU_APIC_VECTOR);
- vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR;
- }
- else
- {
- apic_write_around(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
- vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
- }
-
if ( type != MSR_TYPE_GLOBAL )
{
u64 mask;
@@ -706,10 +693,6 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
return 0;
}
- /* HW sets the MASK bit when performance counter interrupt occurs*/
- vpmu->hw_lapic_lvtpc = apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED;
- apic_write_around(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
-
return 1;
}
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 63b2158..d94b63c 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -64,6 +64,14 @@ static void __init parse_vpmu_param(char *s)
}
}
+void vpmu_lvtpc_update(uint32_t val)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(current);
+
+ vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | (val & APIC_LVT_MASKED);
+ apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
+}
+
int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported)
{
struct vpmu_struct *vpmu = vcpu_vpmu(current);
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index ddc2748..9c4e65a 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -104,6 +104,7 @@ static inline bool_t vpmu_are_all_set(const struct vpmu_struct *vpmu,
return !!((vpmu->flags & mask) == mask);
}
+void vpmu_lvtpc_update(uint32_t val);
int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported);
int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content);
void vpmu_do_interrupt(struct cpu_user_regs *regs);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 09/23] intel/VPMU: MSR_CORE_PERF_GLOBAL_CTRL should be initialized to zero
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (7 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 08/23] x86/VPMU: Handle APIC_LVTPC accesses Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 10/23] x86/VPMU: Add public xenpmu.h Boris Ostrovsky
` (14 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
MSR_CORE_PERF_GLOBAL_CTRL register should be set zero initially. It is up to
the guest to set it so that counters are enabled.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/vmx/vpmu_core2.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 8b84079..7793145 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -165,14 +165,6 @@ static int core2_get_fixed_pmc_count(void)
return MASK_EXTR(eax, PMU_FIXED_NR_MASK);
}
-static u64 core2_calc_intial_glb_ctrl_msr(void)
-{
- int arch_pmc_bits = (1 << arch_pmc_cnt) - 1;
- u64 fix_pmc_bits = (1 << fixed_pmc_cnt) - 1;
-
- return (fix_pmc_bits << 32) | arch_pmc_bits;
-}
-
/* edx bits 5-12: Bit width of fixed-function performance counters */
static int core2_get_bitwidth_fix_count(void)
{
@@ -373,8 +365,7 @@ static int core2_vpmu_alloc_resource(struct vcpu *v)
if ( vmx_add_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
goto out_err;
- vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL,
- core2_calc_intial_glb_ctrl_msr());
+ vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
core2_vpmu_cxt = xzalloc_bytes(sizeof(struct core2_vpmu_context) +
(arch_pmc_cnt-1)*sizeof(struct arch_msr_pair));
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 10/23] x86/VPMU: Add public xenpmu.h
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (8 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 09/23] intel/VPMU: MSR_CORE_PERF_GLOBAL_CTRL should be initialized to zero Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 11/23] x86/VPMU: Make vpmu not HVM-specific Boris Ostrovsky
` (13 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Add pmu.h header files, move various macros and structures that will be
shared between hypervisor and PV guests to it.
Move MSR banks out of architectural PMU structures to allow for larger sizes
in the future. The banks are allocated immediately after the context and
PMU structures store offsets to them.
While making these updates, also:
* Remove unused vpmu_domain() macro from vpmu.h
* Convert msraddr_to_bitpos() into an inline and make it a little faster by
realizing that all Intel's PMU-related MSRs are in the lower MSR range.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/svm/vpmu.c | 83 +++++++++++----------
xen/arch/x86/hvm/vmx/vpmu_core2.c | 123 +++++++++++++++++--------------
xen/arch/x86/hvm/vpmu.c | 10 +++
xen/arch/x86/oprofile/op_model_ppro.c | 6 +-
xen/include/Makefile | 3 +-
xen/include/asm-x86/hvm/vmx/vpmu_core2.h | 32 --------
xen/include/asm-x86/hvm/vpmu.h | 16 ++--
xen/include/public/arch-arm.h | 3 +
xen/include/public/arch-x86/pmu.h | 91 +++++++++++++++++++++++
xen/include/public/pmu.h | 38 ++++++++++
xen/include/xlat.lst | 4 +
11 files changed, 275 insertions(+), 134 deletions(-)
delete mode 100644 xen/include/asm-x86/hvm/vmx/vpmu_core2.h
create mode 100644 xen/include/public/arch-x86/pmu.h
create mode 100644 xen/include/public/pmu.h
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 64dc167..545962d 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -30,10 +30,7 @@
#include <asm/apic.h>
#include <asm/hvm/vlapic.h>
#include <asm/hvm/vpmu.h>
-
-#define F10H_NUM_COUNTERS 4
-#define F15H_NUM_COUNTERS 6
-#define MAX_NUM_COUNTERS F15H_NUM_COUNTERS
+#include <public/pmu.h>
#define MSR_F10H_EVNTSEL_GO_SHIFT 40
#define MSR_F10H_EVNTSEL_EN_SHIFT 22
@@ -49,6 +46,9 @@ static const u32 __read_mostly *counters;
static const u32 __read_mostly *ctrls;
static bool_t __read_mostly k7_counters_mirrored;
+#define F10H_NUM_COUNTERS 4
+#define F15H_NUM_COUNTERS 6
+
/* PMU Counter MSRs. */
static const u32 AMD_F10H_COUNTERS[] = {
MSR_K7_PERFCTR0,
@@ -83,12 +83,14 @@ static const u32 AMD_F15H_CTRLS[] = {
MSR_AMD_FAM15H_EVNTSEL5
};
-/* storage for context switching */
-struct amd_vpmu_context {
- u64 counters[MAX_NUM_COUNTERS];
- u64 ctrls[MAX_NUM_COUNTERS];
- bool_t msr_bitmap_set;
-};
+/* Use private context as a flag for MSR bitmap */
+#define msr_bitmap_on(vpmu) do { \
+ (vpmu)->priv_context = (void *)-1L; \
+ } while (0)
+#define msr_bitmap_off(vpmu) do { \
+ (vpmu)->priv_context = NULL; \
+ } while (0)
+#define is_msr_bitmap_on(vpmu) ((vpmu)->priv_context != NULL)
static inline int get_pmu_reg_type(u32 addr)
{
@@ -142,7 +144,6 @@ static void amd_vpmu_set_msr_bitmap(struct vcpu *v)
{
unsigned int i;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctxt = vpmu->context;
for ( i = 0; i < num_counters; i++ )
{
@@ -150,14 +151,13 @@ static void amd_vpmu_set_msr_bitmap(struct vcpu *v)
svm_intercept_msr(v, ctrls[i], MSR_INTERCEPT_WRITE);
}
- ctxt->msr_bitmap_set = 1;
+ msr_bitmap_on(vpmu);
}
static void amd_vpmu_unset_msr_bitmap(struct vcpu *v)
{
unsigned int i;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctxt = vpmu->context;
for ( i = 0; i < num_counters; i++ )
{
@@ -165,7 +165,7 @@ static void amd_vpmu_unset_msr_bitmap(struct vcpu *v)
svm_intercept_msr(v, ctrls[i], MSR_INTERCEPT_RW);
}
- ctxt->msr_bitmap_set = 0;
+ msr_bitmap_off(vpmu);
}
static int amd_vpmu_do_interrupt(struct cpu_user_regs *regs)
@@ -177,19 +177,22 @@ static inline void context_load(struct vcpu *v)
{
unsigned int i;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctxt = vpmu->context;
+ struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
+ uint64_t *counter_regs = vpmu_reg_pointer(ctxt, counters);
+ uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls);
for ( i = 0; i < num_counters; i++ )
{
- wrmsrl(counters[i], ctxt->counters[i]);
- wrmsrl(ctrls[i], ctxt->ctrls[i]);
+ wrmsrl(counters[i], counter_regs[i]);
+ wrmsrl(ctrls[i], ctrl_regs[i]);
}
}
static void amd_vpmu_load(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctxt = vpmu->context;
+ struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
+ uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls);
vpmu_reset(vpmu, VPMU_FROZEN);
@@ -198,7 +201,7 @@ static void amd_vpmu_load(struct vcpu *v)
unsigned int i;
for ( i = 0; i < num_counters; i++ )
- wrmsrl(ctrls[i], ctxt->ctrls[i]);
+ wrmsrl(ctrls[i], ctrl_regs[i]);
return;
}
@@ -212,17 +215,17 @@ static inline void context_save(struct vcpu *v)
{
unsigned int i;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctxt = vpmu->context;
+ struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
+ uint64_t *counter_regs = vpmu_reg_pointer(ctxt, counters);
/* No need to save controls -- they are saved in amd_vpmu_do_wrmsr */
for ( i = 0; i < num_counters; i++ )
- rdmsrl(counters[i], ctxt->counters[i]);
+ rdmsrl(counters[i], counter_regs[i]);
}
static int amd_vpmu_save(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctx = vpmu->context;
unsigned int i;
/*
@@ -245,7 +248,7 @@ static int amd_vpmu_save(struct vcpu *v)
context_save(v);
if ( !vpmu_is_set(vpmu, VPMU_RUNNING) &&
- has_hvm_container_vcpu(v) && ctx->msr_bitmap_set )
+ has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
amd_vpmu_unset_msr_bitmap(v);
return 1;
@@ -256,7 +259,9 @@ static void context_update(unsigned int msr, u64 msr_content)
unsigned int i;
struct vcpu *v = current;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct amd_vpmu_context *ctxt = vpmu->context;
+ struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
+ uint64_t *counter_regs = vpmu_reg_pointer(ctxt, counters);
+ uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls);
if ( k7_counters_mirrored &&
((msr >= MSR_K7_EVNTSEL0) && (msr <= MSR_K7_PERFCTR3)) )
@@ -268,12 +273,12 @@ static void context_update(unsigned int msr, u64 msr_content)
{
if ( msr == ctrls[i] )
{
- ctxt->ctrls[i] = msr_content;
+ ctrl_regs[i] = msr_content;
return;
}
else if (msr == counters[i] )
{
- ctxt->counters[i] = msr_content;
+ counter_regs[i] = msr_content;
return;
}
}
@@ -303,8 +308,7 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
return 1;
vpmu_set(vpmu, VPMU_RUNNING);
- if ( has_hvm_container_vcpu(v) &&
- !((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
+ if ( has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
amd_vpmu_set_msr_bitmap(v);
}
@@ -313,8 +317,7 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
(is_pmu_enabled(msr_content) == 0) && vpmu_is_set(vpmu, VPMU_RUNNING) )
{
vpmu_reset(vpmu, VPMU_RUNNING);
- if ( has_hvm_container_vcpu(v) &&
- ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
+ if ( has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
amd_vpmu_unset_msr_bitmap(v);
release_pmu_ownship(PMU_OWNER_HVM);
}
@@ -355,7 +358,7 @@ static int amd_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
static int amd_vpmu_initialise(struct vcpu *v)
{
- struct amd_vpmu_context *ctxt;
+ struct xen_pmu_amd_ctxt *ctxt;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
uint8_t family = current_cpu_data.x86;
@@ -385,7 +388,8 @@ static int amd_vpmu_initialise(struct vcpu *v)
}
}
- ctxt = xzalloc(struct amd_vpmu_context);
+ ctxt = xzalloc_bytes(sizeof(*ctxt) +
+ 2 * sizeof(uint64_t) * num_counters);
if ( !ctxt )
{
gdprintk(XENLOG_WARNING, "Insufficient memory for PMU, "
@@ -394,7 +398,11 @@ static int amd_vpmu_initialise(struct vcpu *v)
return -ENOMEM;
}
+ ctxt->counters = sizeof(*ctxt);
+ ctxt->ctrls = ctxt->counters + sizeof(uint64_t) * num_counters;
+
vpmu->context = ctxt;
+ vpmu->priv_context = NULL;
vpmu_set(vpmu, VPMU_CONTEXT_ALLOCATED);
return 0;
}
@@ -403,8 +411,7 @@ static void amd_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- if ( has_hvm_container_vcpu(v) &&
- ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
+ if ( has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
amd_vpmu_unset_msr_bitmap(v);
xfree(vpmu->context);
@@ -421,7 +428,9 @@ static void amd_vpmu_destroy(struct vcpu *v)
static void amd_vpmu_dump(const struct vcpu *v)
{
const struct vpmu_struct *vpmu = vcpu_vpmu(v);
- const struct amd_vpmu_context *ctxt = vpmu->context;
+ const struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
+ const uint64_t *counter_regs = vpmu_reg_pointer(ctxt, counters);
+ const uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls);
unsigned int i;
printk(" VPMU state: 0x%x ", vpmu->flags);
@@ -451,8 +460,8 @@ static void amd_vpmu_dump(const struct vcpu *v)
rdmsrl(ctrls[i], ctrl);
rdmsrl(counters[i], cntr);
printk(" %#x: %#lx (%#lx in HW) %#x: %#lx (%#lx in HW)\n",
- ctrls[i], ctxt->ctrls[i], ctrl,
- counters[i], ctxt->counters[i], cntr);
+ ctrls[i], ctrl_regs[i], ctrl,
+ counters[i], counter_regs[i], cntr);
}
}
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 7793145..c2405bf 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -35,8 +35,8 @@
#include <asm/hvm/vmx/vmcs.h>
#include <public/sched.h>
#include <public/hvm/save.h>
+#include <public/pmu.h>
#include <asm/hvm/vpmu.h>
-#include <asm/hvm/vmx/vpmu_core2.h>
/*
* See Intel SDM Vol 2a Instruction Set Reference chapter 3 for CPUID
@@ -68,6 +68,10 @@
#define MSR_PMC_ALIAS_MASK (~(MSR_IA32_PERFCTR0 ^ MSR_IA32_A_PERFCTR0))
static bool_t __read_mostly full_width_write;
+/* Intel-specific VPMU features */
+#define VPMU_CPU_HAS_DS 0x100 /* Has Debug Store */
+#define VPMU_CPU_HAS_BTS 0x200 /* Has Branch Trace Store */
+
/*
* MSR_CORE_PERF_FIXED_CTR_CTRL contains the configuration of all fixed
* counters. 4 bits for every counter.
@@ -75,17 +79,6 @@ static bool_t __read_mostly full_width_write;
#define FIXED_CTR_CTRL_BITS 4
#define FIXED_CTR_CTRL_MASK ((1 << FIXED_CTR_CTRL_BITS) - 1)
-#define VPMU_CORE2_MAX_FIXED_PMCS 4
-struct core2_vpmu_context {
- u64 fixed_ctrl;
- u64 ds_area;
- u64 pebs_enable;
- u64 global_ovf_status;
- u64 enabled_cntrs; /* Follows PERF_GLOBAL_CTRL MSR format */
- u64 fix_counters[VPMU_CORE2_MAX_FIXED_PMCS];
- struct arch_msr_pair arch_msr_pair[1];
-};
-
/* Number of general-purpose and fixed performance counters */
static unsigned int __read_mostly arch_pmc_cnt, fixed_pmc_cnt;
@@ -222,6 +215,12 @@ static int is_core2_vpmu_msr(u32 msr_index, int *type, int *index)
}
}
+static inline int msraddr_to_bitpos(int x)
+{
+ ASSERT(x == (x & 0x1fff));
+ return x;
+}
+
static void core2_vpmu_set_msr_bitmap(unsigned long *msr_bitmap)
{
int i;
@@ -291,12 +290,15 @@ static void core2_vpmu_unset_msr_bitmap(unsigned long *msr_bitmap)
static inline void __core2_vpmu_save(struct vcpu *v)
{
int i;
- struct core2_vpmu_context *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+ uint64_t *fixed_counters = vpmu_reg_pointer(core2_vpmu_cxt, fixed_counters);
+ struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
+ vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
for ( i = 0; i < fixed_pmc_cnt; i++ )
- rdmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, core2_vpmu_cxt->fix_counters[i]);
+ rdmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, fixed_counters[i]);
for ( i = 0; i < arch_pmc_cnt; i++ )
- rdmsrl(MSR_IA32_PERFCTR0 + i, core2_vpmu_cxt->arch_msr_pair[i].counter);
+ rdmsrl(MSR_IA32_PERFCTR0 + i, xen_pmu_cntr_pair[i].counter);
}
static int core2_vpmu_save(struct vcpu *v)
@@ -319,10 +321,13 @@ static int core2_vpmu_save(struct vcpu *v)
static inline void __core2_vpmu_load(struct vcpu *v)
{
unsigned int i, pmc_start;
- struct core2_vpmu_context *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+ uint64_t *fixed_counters = vpmu_reg_pointer(core2_vpmu_cxt, fixed_counters);
+ struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
+ vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
for ( i = 0; i < fixed_pmc_cnt; i++ )
- wrmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, core2_vpmu_cxt->fix_counters[i]);
+ wrmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, fixed_counters[i]);
if ( full_width_write )
pmc_start = MSR_IA32_A_PERFCTR0;
@@ -330,8 +335,8 @@ static inline void __core2_vpmu_load(struct vcpu *v)
pmc_start = MSR_IA32_PERFCTR0;
for ( i = 0; i < arch_pmc_cnt; i++ )
{
- wrmsrl(pmc_start + i, core2_vpmu_cxt->arch_msr_pair[i].counter);
- wrmsrl(MSR_P6_EVNTSEL(i), core2_vpmu_cxt->arch_msr_pair[i].control);
+ wrmsrl(pmc_start + i, xen_pmu_cntr_pair[i].counter);
+ wrmsrl(MSR_P6_EVNTSEL(i), xen_pmu_cntr_pair[i].control);
}
wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, core2_vpmu_cxt->fixed_ctrl);
@@ -354,7 +359,8 @@ static void core2_vpmu_load(struct vcpu *v)
static int core2_vpmu_alloc_resource(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct core2_vpmu_context *core2_vpmu_cxt;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt = NULL;
+ uint64_t *p = NULL;
if ( !acquire_pmu_ownership(PMU_OWNER_HVM) )
return 0;
@@ -367,12 +373,20 @@ static int core2_vpmu_alloc_resource(struct vcpu *v)
goto out_err;
vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
- core2_vpmu_cxt = xzalloc_bytes(sizeof(struct core2_vpmu_context) +
- (arch_pmc_cnt-1)*sizeof(struct arch_msr_pair));
- if ( !core2_vpmu_cxt )
+ core2_vpmu_cxt = xzalloc_bytes(sizeof(*core2_vpmu_cxt) +
+ sizeof(uint64_t) * fixed_pmc_cnt +
+ sizeof(struct xen_pmu_cntr_pair) *
+ arch_pmc_cnt);
+ p = xzalloc(uint64_t);
+ if ( !core2_vpmu_cxt || !p )
goto out_err;
- vpmu->context = (void *)core2_vpmu_cxt;
+ core2_vpmu_cxt->fixed_counters = sizeof(*core2_vpmu_cxt);
+ core2_vpmu_cxt->arch_counters = core2_vpmu_cxt->fixed_counters +
+ sizeof(uint64_t) * fixed_pmc_cnt;
+
+ vpmu->context = core2_vpmu_cxt;
+ vpmu->priv_context = p;
vpmu_set(vpmu, VPMU_CONTEXT_ALLOCATED);
@@ -381,6 +395,9 @@ static int core2_vpmu_alloc_resource(struct vcpu *v)
out_err:
release_pmu_ownship(PMU_OWNER_HVM);
+ xfree(core2_vpmu_cxt);
+ xfree(p);
+
printk("Failed to allocate VPMU resources for domain %u vcpu %u\n",
v->vcpu_id, v->domain->domain_id);
@@ -418,7 +435,8 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
int type = -1, index = -1;
struct vcpu *v = current;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct core2_vpmu_context *core2_vpmu_cxt = NULL;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt;
+ uint64_t *enabled_cntrs;
if ( !core2_vpmu_msr_common_check(msr, &type, &index) )
{
@@ -446,10 +464,11 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
ASSERT(!supported);
core2_vpmu_cxt = vpmu->context;
+ enabled_cntrs = vpmu->priv_context;
switch ( msr )
{
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
- core2_vpmu_cxt->global_ovf_status &= ~msr_content;
+ core2_vpmu_cxt->global_status &= ~msr_content;
return 1;
case MSR_CORE_PERF_GLOBAL_STATUS:
gdprintk(XENLOG_INFO, "Can not write readonly MSR: "
@@ -483,15 +502,14 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
break;
case MSR_CORE_PERF_FIXED_CTR_CTRL:
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
- core2_vpmu_cxt->enabled_cntrs &=
- ~(((1ULL << VPMU_CORE2_MAX_FIXED_PMCS) - 1) << 32);
+ *enabled_cntrs &= ~(((1ULL << fixed_pmc_cnt) - 1) << 32);
if ( msr_content != 0 )
{
u64 val = msr_content;
for ( i = 0; i < fixed_pmc_cnt; i++ )
{
if ( val & 3 )
- core2_vpmu_cxt->enabled_cntrs |= (1ULL << 32) << i;
+ *enabled_cntrs |= (1ULL << 32) << i;
val >>= FIXED_CTR_CTRL_BITS;
}
}
@@ -502,19 +520,21 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
tmp = msr - MSR_P6_EVNTSEL(0);
if ( tmp >= 0 && tmp < arch_pmc_cnt )
{
+ struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
+ vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
+
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
if ( msr_content & (1ULL << 22) )
- core2_vpmu_cxt->enabled_cntrs |= 1ULL << tmp;
+ *enabled_cntrs |= 1ULL << tmp;
else
- core2_vpmu_cxt->enabled_cntrs &= ~(1ULL << tmp);
+ *enabled_cntrs &= ~(1ULL << tmp);
- core2_vpmu_cxt->arch_msr_pair[tmp].control = msr_content;
+ xen_pmu_cntr_pair[tmp].control = msr_content;
}
}
- if ( (global_ctrl & core2_vpmu_cxt->enabled_cntrs) ||
- (core2_vpmu_cxt->ds_area != 0) )
+ if ( (global_ctrl & *enabled_cntrs) || (core2_vpmu_cxt->ds_area != 0) )
vpmu_set(vpmu, VPMU_RUNNING);
else
vpmu_reset(vpmu, VPMU_RUNNING);
@@ -560,7 +580,7 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
int type = -1, index = -1;
struct vcpu *v = current;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct core2_vpmu_context *core2_vpmu_cxt = NULL;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt;
if ( core2_vpmu_msr_common_check(msr, &type, &index) )
{
@@ -571,7 +591,7 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
*msr_content = 0;
break;
case MSR_CORE_PERF_GLOBAL_STATUS:
- *msr_content = core2_vpmu_cxt->global_ovf_status;
+ *msr_content = core2_vpmu_cxt->global_status;
break;
case MSR_CORE_PERF_GLOBAL_CTRL:
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
@@ -620,10 +640,12 @@ static void core2_vpmu_dump(const struct vcpu *v)
{
const struct vpmu_struct *vpmu = vcpu_vpmu(v);
unsigned int i;
- const struct core2_vpmu_context *core2_vpmu_cxt = NULL;
+ const struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vpmu->context;
u64 val;
+ uint64_t *fixed_counters;
+ struct xen_pmu_cntr_pair *cntr_pair;
- if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
+ if ( !core2_vpmu_cxt || !vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
return;
if ( !vpmu_is_set(vpmu, VPMU_RUNNING) )
@@ -636,16 +658,15 @@ static void core2_vpmu_dump(const struct vcpu *v)
}
printk(" vPMU running\n");
- core2_vpmu_cxt = vpmu->context;
+
+ cntr_pair = vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
+ fixed_counters = vpmu_reg_pointer(core2_vpmu_cxt, fixed_counters);
/* Print the contents of the counter and its configuration msr. */
for ( i = 0; i < arch_pmc_cnt; i++ )
- {
- const struct arch_msr_pair *msr_pair = core2_vpmu_cxt->arch_msr_pair;
-
printk(" general_%d: 0x%016lx ctrl: 0x%016lx\n",
- i, msr_pair[i].counter, msr_pair[i].control);
- }
+ i, cntr_pair[i].counter, cntr_pair[i].control);
+
/*
* The configuration of the fixed counter is 4 bits each in the
* MSR_CORE_PERF_FIXED_CTR_CTRL.
@@ -654,7 +675,7 @@ static void core2_vpmu_dump(const struct vcpu *v)
for ( i = 0; i < fixed_pmc_cnt; i++ )
{
printk(" fixed_%d: 0x%016lx ctrl: %#lx\n",
- i, core2_vpmu_cxt->fix_counters[i],
+ i, fixed_counters[i],
val & FIXED_CTR_CTRL_MASK);
val >>= FIXED_CTR_CTRL_BITS;
}
@@ -665,14 +686,14 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
struct vcpu *v = current;
u64 msr_content;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- struct core2_vpmu_context *core2_vpmu_cxt = vpmu->context;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vpmu->context;
rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, msr_content);
if ( msr_content )
{
if ( is_pmc_quirk )
handle_pmc_quirk(msr_content);
- core2_vpmu_cxt->global_ovf_status |= msr_content;
+ core2_vpmu_cxt->global_status |= msr_content;
msr_content = 0xC000000700000000 | ((1 << arch_pmc_cnt) - 1);
wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, msr_content);
}
@@ -739,13 +760,6 @@ static int core2_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
arch_pmc_cnt = core2_get_arch_pmc_count();
fixed_pmc_cnt = core2_get_fixed_pmc_count();
- if ( fixed_pmc_cnt > VPMU_CORE2_MAX_FIXED_PMCS )
- {
- fixed_pmc_cnt = VPMU_CORE2_MAX_FIXED_PMCS;
- printk(XENLOG_G_WARNING "Limiting number of fixed counters to %d\n",
- fixed_pmc_cnt);
- }
-
check_pmc_quirk();
return 0;
}
@@ -755,6 +769,7 @@ static void core2_vpmu_destroy(struct vcpu *v)
struct vpmu_struct *vpmu = vcpu_vpmu(v);
xfree(vpmu->context);
+ xfree(vpmu->priv_context);
if ( has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
release_pmu_ownship(PMU_OWNER_HVM);
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index d94b63c..f31c5b6 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -31,6 +31,13 @@
#include <asm/hvm/svm/svm.h>
#include <asm/hvm/svm/vmcb.h>
#include <asm/apic.h>
+#include <public/pmu.h>
+
+#include <compat/pmu.h>
+CHECK_pmu_intel_ctxt;
+CHECK_pmu_amd_ctxt;
+CHECK_pmu_cntr_pair;
+CHECK_pmu_regs;
/*
* "vpmu" : vpmu generally enabled
@@ -230,6 +237,9 @@ void vpmu_initialise(struct vcpu *v)
if ( is_pvh_vcpu(v) )
return;
+ BUILD_BUG_ON(sizeof(struct xen_pmu_intel_ctxt) > XENPMU_CTXT_PAD_SZ);
+ BUILD_BUG_ON(sizeof(struct xen_pmu_amd_ctxt) > XENPMU_CTXT_PAD_SZ);
+
if ( vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
vpmu_destroy(v);
vpmu_clear(vpmu);
diff --git a/xen/arch/x86/oprofile/op_model_ppro.c b/xen/arch/x86/oprofile/op_model_ppro.c
index aa99e4d..ca429a1 100644
--- a/xen/arch/x86/oprofile/op_model_ppro.c
+++ b/xen/arch/x86/oprofile/op_model_ppro.c
@@ -20,11 +20,15 @@
#include <asm/regs.h>
#include <asm/current.h>
#include <asm/hvm/vpmu.h>
-#include <asm/hvm/vmx/vpmu_core2.h>
#include "op_x86_model.h"
#include "op_counter.h"
+struct arch_msr_pair {
+ u64 counter;
+ u64 control;
+};
+
/*
* Intel "Architectural Performance Monitoring" CPUID
* detection/enumeration details:
diff --git a/xen/include/Makefile b/xen/include/Makefile
index f7ccbc9..14ea8da 100644
--- a/xen/include/Makefile
+++ b/xen/include/Makefile
@@ -23,10 +23,11 @@ headers-y := \
compat/xen.h \
compat/xencomm.h \
compat/xenoprof.h
+headers-$(CONFIG_X86) += compat/arch-x86/pmu.h
headers-$(CONFIG_X86) += compat/arch-x86/xen-mca.h
headers-$(CONFIG_X86) += compat/arch-x86/xen.h
headers-$(CONFIG_X86) += compat/arch-x86/xen-$(compat-arch-y).h
-headers-y += compat/arch-$(compat-arch-y).h compat/xlat.h
+headers-y += compat/arch-$(compat-arch-y).h compat/pmu.h compat/xlat.h
headers-$(FLASK_ENABLE) += compat/xsm/flask_op.h
cppflags-y := -include public/xen-compat.h
diff --git a/xen/include/asm-x86/hvm/vmx/vpmu_core2.h b/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
deleted file mode 100644
index 410372d..0000000
--- a/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
+++ /dev/null
@@ -1,32 +0,0 @@
-
-/*
- * vpmu_core2.h: CORE 2 specific PMU virtualization for HVM domain.
- *
- * Copyright (c) 2007, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- * Author: Haitao Shan <haitao.shan@intel.com>
- */
-
-#ifndef __ASM_X86_HVM_VPMU_CORE_H_
-#define __ASM_X86_HVM_VPMU_CORE_H_
-
-struct arch_msr_pair {
- u64 counter;
- u64 control;
-};
-
-#endif /* __ASM_X86_HVM_VPMU_CORE_H_ */
-
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 9c4e65a..83eea7e 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -22,6 +22,8 @@
#ifndef __ASM_X86_HVM_VPMU_H_
#define __ASM_X86_HVM_VPMU_H_
+#include <public/pmu.h>
+
/*
* Flag bits given as a string on the hypervisor boot parameter 'vpmu'.
* See arch/x86/hvm/vpmu.c.
@@ -29,12 +31,9 @@
#define VPMU_BOOT_ENABLED 0x1 /* vpmu generally enabled. */
#define VPMU_BOOT_BTS 0x2 /* Intel BTS feature wanted. */
-
-#define msraddr_to_bitpos(x) (((x)&0xffff) + ((x)>>31)*0x2000)
#define vcpu_vpmu(vcpu) (&((vcpu)->arch.hvm_vcpu.vpmu))
#define vpmu_vcpu(vpmu) (container_of((vpmu), struct vcpu, \
arch.hvm_vcpu.vpmu))
-#define vpmu_domain(vpmu) (vpmu_vcpu(vpmu)->domain)
#define MSR_TYPE_COUNTER 0
#define MSR_TYPE_CTRL 1
@@ -42,6 +41,9 @@
#define MSR_TYPE_ARCH_COUNTER 3
#define MSR_TYPE_ARCH_CTRL 4
+/* Start of PMU register bank */
+#define vpmu_reg_pointer(ctxt, offset) ((void *)((uintptr_t)ctxt + \
+ (uintptr_t)ctxt->offset))
/* Arch specific operations shared by all vpmus */
struct arch_vpmu_ops {
@@ -65,7 +67,8 @@ struct vpmu_struct {
u32 flags;
u32 last_pcpu;
u32 hw_lapic_lvtpc;
- void *context;
+ void *context; /* May be shared with PV guest */
+ void *priv_context; /* hypervisor-only */
struct arch_vpmu_ops *arch_vpmu_ops;
};
@@ -77,11 +80,6 @@ struct vpmu_struct {
#define VPMU_FROZEN 0x10 /* Stop counters while VCPU is not running */
#define VPMU_PASSIVE_DOMAIN_ALLOCATED 0x20
-/* VPMU features */
-#define VPMU_CPU_HAS_DS 0x100 /* Has Debug Store */
-#define VPMU_CPU_HAS_BTS 0x200 /* Has Branch Trace Store */
-
-
static inline void vpmu_set(struct vpmu_struct *vpmu, const u32 mask)
{
vpmu->flags |= mask;
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index e711606..f694369 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -423,6 +423,9 @@ typedef uint64_t xen_callback_t;
#endif
+/* Stub definition of PMU structure */
+typedef struct xen_pmu_arch {} xen_pmu_arch_t;
+
#endif /* __XEN_PUBLIC_ARCH_ARM_H__ */
/*
diff --git a/xen/include/public/arch-x86/pmu.h b/xen/include/public/arch-x86/pmu.h
new file mode 100644
index 0000000..8bbe341
--- /dev/null
+++ b/xen/include/public/arch-x86/pmu.h
@@ -0,0 +1,91 @@
+#ifndef __XEN_PUBLIC_ARCH_X86_PMU_H__
+#define __XEN_PUBLIC_ARCH_X86_PMU_H__
+
+/* x86-specific PMU definitions */
+
+/* AMD PMU registers and structures */
+struct xen_pmu_amd_ctxt {
+ /* Offsets to counter and control MSRs (relative to xen_pmu_arch.c.amd) */
+ uint32_t counters;
+ uint32_t ctrls;
+};
+typedef struct xen_pmu_amd_ctxt xen_pmu_amd_ctxt_t;
+DEFINE_XEN_GUEST_HANDLE(xen_pmu_amd_ctxt_t);
+
+/* Intel PMU registers and structures */
+struct xen_pmu_cntr_pair {
+ uint64_t counter;
+ uint64_t control;
+};
+typedef struct xen_pmu_cntr_pair xen_pmu_cntr_pair_t;
+DEFINE_XEN_GUEST_HANDLE(xen_pmu_cntr_pair_t);
+
+struct xen_pmu_intel_ctxt {
+ uint64_t global_ctrl;
+ uint64_t global_ovf_ctrl;
+ uint64_t global_status;
+ uint64_t fixed_ctrl;
+ uint64_t ds_area;
+ uint64_t pebs_enable;
+ uint64_t debugctl;
+ /*
+ * Offsets to fixed and architectural counter MSRs (relative to
+ * xen_pmu_arch.c.intel)
+ */
+ uint32_t fixed_counters;
+ uint32_t arch_counters;
+};
+typedef struct xen_pmu_intel_ctxt xen_pmu_intel_ctxt_t;
+DEFINE_XEN_GUEST_HANDLE(xen_pmu_intel_ctxt_t);
+
+/* Sampled domain's registers */
+struct xen_pmu_regs {
+ uint64_t ip;
+ uint64_t sp;
+ uint64_t flags;
+ uint16_t cs;
+ uint16_t ss;
+ uint8_t cpl;
+ uint8_t pad[3];
+};
+typedef struct xen_pmu_regs xen_pmu_regs_t;
+DEFINE_XEN_GUEST_HANDLE(xen_pmu_regs_t);
+
+struct xen_pmu_arch {
+ union {
+ struct xen_pmu_regs regs;
+ /* Padding for adding new registers to xen_pmu_regs in the future */
+#define XENPMU_REGS_PAD_SZ 64
+ uint8_t pad[XENPMU_REGS_PAD_SZ];
+ } r;
+ uint64_t pmu_flags;
+ union {
+ uint32_t lapic_lvtpc;
+ uint64_t pad;
+ } l;
+ union {
+ struct xen_pmu_amd_ctxt amd;
+ struct xen_pmu_intel_ctxt intel;
+
+ /*
+ * Padding for contexts (fixed parts only, does not include MSR banks
+ * that are specified by offsets
+ */
+#define XENPMU_CTXT_PAD_SZ 128
+ uint8_t pad[XENPMU_CTXT_PAD_SZ];
+ } c;
+};
+typedef struct xen_pmu_arch xen_pmu_arch_t;
+DEFINE_XEN_GUEST_HANDLE(xen_pmu_arch_t);
+
+#endif /* __XEN_PUBLIC_ARCH_X86_PMU_H__ */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
new file mode 100644
index 0000000..f97106d
--- /dev/null
+++ b/xen/include/public/pmu.h
@@ -0,0 +1,38 @@
+#ifndef __XEN_PUBLIC_PMU_H__
+#define __XEN_PUBLIC_PMU_H__
+
+#include "xen.h"
+#if defined(__i386__) || defined(__x86_64__)
+#include "arch-x86/pmu.h"
+#elif defined (__arm__) || defined (__aarch64__)
+#include "arch-arm.h"
+#else
+#error "Unsupported architecture"
+#endif
+
+#define XENPMU_VER_MAJ 0
+#define XENPMU_VER_MIN 1
+
+
+/* Shared between hypervisor and PV domain */
+struct xen_pmu_data {
+ uint32_t domain_id;
+ uint32_t vcpu_id;
+ uint32_t pcpu_id;
+
+ uint32_t pad;
+
+ xen_pmu_arch_t pmu;
+};
+
+#endif /* __XEN_PUBLIC_PMU_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index eb40aab..b6bef8c 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -103,6 +103,10 @@
! vcpu_set_singleshot_timer vcpu.h
? xenoprof_init xenoprof.h
? xenoprof_passive xenoprof.h
+? pmu_amd_ctxt arch-x86/pmu.h
+? pmu_cntr_pair arch-x86/pmu.h
+? pmu_intel_ctxt arch-x86/pmu.h
+? pmu_regs arch-x86/pmu.h
? flask_access xsm/flask_op.h
! flask_boolean xsm/flask_op.h
? flask_cache_stats xsm/flask_op.h
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 11/23] x86/VPMU: Make vpmu not HVM-specific
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (9 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 10/23] x86/VPMU: Add public xenpmu.h Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 12/23] x86/VPMU: Replace vcpu with vpmu as argument to some routines Boris Ostrovsky
` (12 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
vpmu structure will be used for both HVM and PV guests. Move it from
hvm_vcpu to arch_vcpu.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/include/asm-x86/domain.h | 2 ++
xen/include/asm-x86/hvm/vcpu.h | 3 ---
xen/include/asm-x86/hvm/vpmu.h | 5 ++---
3 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 6a77a93..be4d1dc 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -426,6 +426,8 @@ struct arch_vcpu
void (*ctxt_switch_from) (struct vcpu *);
void (*ctxt_switch_to) (struct vcpu *);
+ struct vpmu_struct vpmu;
+
/* Virtual Machine Extensions */
union {
struct pv_vcpu pv_vcpu;
diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h
index 01e0665..71a5b15 100644
--- a/xen/include/asm-x86/hvm/vcpu.h
+++ b/xen/include/asm-x86/hvm/vcpu.h
@@ -151,9 +151,6 @@ struct hvm_vcpu {
u32 msr_tsc_aux;
u64 msr_tsc_adjust;
- /* VPMU */
- struct vpmu_struct vpmu;
-
union {
struct arch_vmx_struct vmx;
struct arch_svm_struct svm;
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 83eea7e..82bfa0e 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -31,9 +31,8 @@
#define VPMU_BOOT_ENABLED 0x1 /* vpmu generally enabled. */
#define VPMU_BOOT_BTS 0x2 /* Intel BTS feature wanted. */
-#define vcpu_vpmu(vcpu) (&((vcpu)->arch.hvm_vcpu.vpmu))
-#define vpmu_vcpu(vpmu) (container_of((vpmu), struct vcpu, \
- arch.hvm_vcpu.vpmu))
+#define vcpu_vpmu(vcpu) (&(vcpu)->arch.vpmu)
+#define vpmu_vcpu(vpmu) container_of((vpmu), struct vcpu, arch.vpmu)
#define MSR_TYPE_COUNTER 0
#define MSR_TYPE_CTRL 1
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 12/23] x86/VPMU: Replace vcpu with vpmu as argument to some routines
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (10 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 11/23] x86/VPMU: Make vpmu not HVM-specific Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 13/23] x86/VPMU: Interface for setting PMU mode and flags Boris Ostrovsky
` (11 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
A subsequent patch will add an inline routine to vpmu.h that will call vpmu_load().
This inline will try to access vcpu->vpmu which is not possible since struct
vcpu may not be fully defined at that point. So we will have that inline pass
vpmu pointer to vpmu_load() instead.
This change slightly simplifies some of vpmu code.
For symmetry also modify vpmu_save() (and vpmu_save_force()) to use vpmu
instead of vcpu.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
xen/arch/x86/domain.c | 4 ++--
xen/arch/x86/hvm/svm/vpmu.c | 23 +++++++++++------------
xen/arch/x86/hvm/vmx/vpmu_core2.c | 24 ++++++++++++------------
xen/arch/x86/hvm/vpmu.c | 31 +++++++++++++------------------
xen/include/asm-x86/hvm/vpmu.h | 26 +++++++++++++-------------
5 files changed, 51 insertions(+), 57 deletions(-)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 11c7d9f..4e45fa8 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1544,7 +1544,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
if ( is_hvm_vcpu(prev) )
{
if (prev != next)
- vpmu_save(prev);
+ vpmu_save(vcpu_vpmu(prev));
if ( !list_empty(&prev->arch.hvm_vcpu.tm_list) )
pt_save_timer(prev);
@@ -1589,7 +1589,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
if (is_hvm_vcpu(next) && (prev != next) )
/* Must be done with interrupts enabled */
- vpmu_load(next);
+ vpmu_load(vcpu_vpmu(next));
context_saved(prev);
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 545962d..72e2561 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -173,10 +173,9 @@ static int amd_vpmu_do_interrupt(struct cpu_user_regs *regs)
return 1;
}
-static inline void context_load(struct vcpu *v)
+static inline void context_load(struct vpmu_struct *vpmu)
{
unsigned int i;
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
uint64_t *counter_regs = vpmu_reg_pointer(ctxt, counters);
uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls);
@@ -188,9 +187,8 @@ static inline void context_load(struct vcpu *v)
}
}
-static void amd_vpmu_load(struct vcpu *v)
+static void amd_vpmu_load(struct vpmu_struct *vpmu)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls);
@@ -208,13 +206,12 @@ static void amd_vpmu_load(struct vcpu *v)
vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
- context_load(v);
+ context_load(vpmu);
}
-static inline void context_save(struct vcpu *v)
+static inline void context_save(struct vpmu_struct *vpmu)
{
unsigned int i;
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
struct xen_pmu_amd_ctxt *ctxt = vpmu->context;
uint64_t *counter_regs = vpmu_reg_pointer(ctxt, counters);
@@ -223,9 +220,9 @@ static inline void context_save(struct vcpu *v)
rdmsrl(counters[i], counter_regs[i]);
}
-static int amd_vpmu_save(struct vcpu *v)
+static int amd_vpmu_save(struct vpmu_struct *vpmu)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct vcpu *v;
unsigned int i;
/*
@@ -245,7 +242,9 @@ static int amd_vpmu_save(struct vcpu *v)
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
return 0;
- context_save(v);
+ context_save(vpmu);
+
+ v = vpmu_vcpu(vpmu);
if ( !vpmu_is_set(vpmu, VPMU_RUNNING) &&
has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
@@ -325,7 +324,7 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED)
|| vpmu_is_set(vpmu, VPMU_FROZEN) )
{
- context_load(v);
+ context_load(vpmu);
vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
vpmu_reset(vpmu, VPMU_FROZEN);
}
@@ -346,7 +345,7 @@ static int amd_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED)
|| vpmu_is_set(vpmu, VPMU_FROZEN) )
{
- context_load(v);
+ context_load(vpmu);
vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
vpmu_reset(vpmu, VPMU_FROZEN);
}
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index c2405bf..ad7c058 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -287,10 +287,10 @@ static void core2_vpmu_unset_msr_bitmap(unsigned long *msr_bitmap)
set_bit(msraddr_to_bitpos(MSR_IA32_DS_AREA), msr_bitmap);
}
-static inline void __core2_vpmu_save(struct vcpu *v)
+static inline void __core2_vpmu_save(struct vpmu_struct *vpmu)
{
int i;
- struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vpmu->context;
uint64_t *fixed_counters = vpmu_reg_pointer(core2_vpmu_cxt, fixed_counters);
struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
@@ -301,14 +301,16 @@ static inline void __core2_vpmu_save(struct vcpu *v)
rdmsrl(MSR_IA32_PERFCTR0 + i, xen_pmu_cntr_pair[i].counter);
}
-static int core2_vpmu_save(struct vcpu *v)
+static int core2_vpmu_save(struct vpmu_struct *vpmu)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct vcpu *v;
if ( !vpmu_are_all_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED) )
return 0;
- __core2_vpmu_save(v);
+ __core2_vpmu_save(vpmu);
+
+ v = vpmu_vcpu(vpmu);
/* Unset PMU MSR bitmap to trap lazy load. */
if ( !vpmu_is_set(vpmu, VPMU_RUNNING) &&
@@ -318,10 +320,10 @@ static int core2_vpmu_save(struct vcpu *v)
return 1;
}
-static inline void __core2_vpmu_load(struct vcpu *v)
+static inline void __core2_vpmu_load(struct vpmu_struct *vpmu)
{
unsigned int i, pmc_start;
- struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+ struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vpmu->context;
uint64_t *fixed_counters = vpmu_reg_pointer(core2_vpmu_cxt, fixed_counters);
struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
@@ -344,16 +346,14 @@ static inline void __core2_vpmu_load(struct vcpu *v)
wrmsrl(MSR_IA32_PEBS_ENABLE, core2_vpmu_cxt->pebs_enable);
}
-static void core2_vpmu_load(struct vcpu *v)
+static void core2_vpmu_load(struct vpmu_struct *vpmu)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
-
if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
return;
vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
- __core2_vpmu_load(v);
+ __core2_vpmu_load(vpmu);
}
static int core2_vpmu_alloc_resource(struct vcpu *v)
@@ -418,7 +418,7 @@ static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
/* Do the lazy load staff. */
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
{
- __core2_vpmu_load(current);
+ __core2_vpmu_load(vpmu);
vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
if ( has_hvm_container_vcpu(current) &&
cpu_has_vmx_msr_bitmap )
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index f31c5b6..752ae0d 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -137,8 +137,7 @@ void vpmu_do_cpuid(unsigned int input,
static void vpmu_save_force(void *arg)
{
- struct vcpu *v = (struct vcpu *)arg;
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct vpmu_struct *vpmu = (struct vpmu_struct *)arg;
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
return;
@@ -146,36 +145,34 @@ static void vpmu_save_force(void *arg)
vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
if ( vpmu->arch_vpmu_ops )
- (void)vpmu->arch_vpmu_ops->arch_vpmu_save(v);
+ vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu);
vpmu_reset(vpmu, VPMU_CONTEXT_SAVE);
per_cpu(last_vcpu, smp_processor_id()) = NULL;
}
-void vpmu_save(struct vcpu *v)
+void vpmu_save(struct vpmu_struct *vpmu)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
int pcpu = smp_processor_id();
if ( !vpmu_are_all_set(vpmu, VPMU_CONTEXT_ALLOCATED | VPMU_CONTEXT_LOADED) )
return;
vpmu->last_pcpu = pcpu;
- per_cpu(last_vcpu, pcpu) = v;
+ per_cpu(last_vcpu, pcpu) = vpmu_vcpu(vpmu);
if ( vpmu->arch_vpmu_ops )
- if ( vpmu->arch_vpmu_ops->arch_vpmu_save(v) )
+ if ( vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu) )
vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
}
-void vpmu_load(struct vcpu *v)
+void vpmu_load(struct vpmu_struct *vpmu)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
int pcpu = smp_processor_id();
- struct vcpu *prev = NULL;
+ struct vcpu *prev;
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
return;
@@ -193,7 +190,7 @@ void vpmu_load(struct vcpu *v)
if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
{
on_selected_cpus(cpumask_of(vpmu->last_pcpu),
- vpmu_save_force, (void *)v, 1);
+ vpmu_save_force, vpmu, 1);
vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
}
}
@@ -203,15 +200,13 @@ void vpmu_load(struct vcpu *v)
prev = per_cpu(last_vcpu, pcpu);
- if ( prev != v && prev )
+ if ( (prev != vpmu_vcpu(vpmu)) && prev )
{
- vpmu = vcpu_vpmu(prev);
+ struct vpmu_struct *vpmu_prev = vcpu_vpmu(prev);
/* Someone ran here before us */
- vpmu_save_force(prev);
- vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
-
- vpmu = vcpu_vpmu(v);
+ vpmu_save_force(vpmu_prev);
+ vpmu_reset(vpmu_prev, VPMU_CONTEXT_LOADED);
}
local_irq_enable();
@@ -224,7 +219,7 @@ void vpmu_load(struct vcpu *v)
{
apic_write_around(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
/* Arch code needs to set VPMU_CONTEXT_LOADED */
- vpmu->arch_vpmu_ops->arch_vpmu_load(v);
+ vpmu->arch_vpmu_ops->arch_vpmu_load(vpmu);
}
}
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 82bfa0e..897d5de 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -44,6 +44,15 @@
#define vpmu_reg_pointer(ctxt, offset) ((void *)((uintptr_t)ctxt + \
(uintptr_t)ctxt->offset))
+struct vpmu_struct {
+ u32 flags;
+ u32 last_pcpu;
+ u32 hw_lapic_lvtpc;
+ void *context; /* May be shared with PV guest */
+ void *priv_context; /* hypervisor-only */
+ struct arch_vpmu_ops *arch_vpmu_ops;
+};
+
/* Arch specific operations shared by all vpmus */
struct arch_vpmu_ops {
int (*do_wrmsr)(unsigned int msr, uint64_t msr_content,
@@ -54,23 +63,14 @@ struct arch_vpmu_ops {
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
void (*arch_vpmu_destroy)(struct vcpu *v);
- int (*arch_vpmu_save)(struct vcpu *v);
- void (*arch_vpmu_load)(struct vcpu *v);
+ int (*arch_vpmu_save)(struct vpmu_struct *vpmu);
+ void (*arch_vpmu_load)(struct vpmu_struct *vpmu);
void (*arch_vpmu_dump)(const struct vcpu *);
};
int vmx_vpmu_initialise(struct vcpu *, unsigned int flags);
int svm_vpmu_initialise(struct vcpu *, unsigned int flags);
-struct vpmu_struct {
- u32 flags;
- u32 last_pcpu;
- u32 hw_lapic_lvtpc;
- void *context; /* May be shared with PV guest */
- void *priv_context; /* hypervisor-only */
- struct arch_vpmu_ops *arch_vpmu_ops;
-};
-
/* VPMU states */
#define VPMU_CONTEXT_ALLOCATED 0x1
#define VPMU_CONTEXT_LOADED 0x2
@@ -109,8 +109,8 @@ void vpmu_do_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
void vpmu_initialise(struct vcpu *v);
void vpmu_destroy(struct vcpu *v);
-void vpmu_save(struct vcpu *v);
-void vpmu_load(struct vcpu *v);
+void vpmu_save(struct vpmu_struct *vpmu);
+void vpmu_load(struct vpmu_struct *vpmu);
void vpmu_dump(struct vcpu *v);
extern int acquire_pmu_ownership(int pmu_ownership);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 13/23] x86/VPMU: Interface for setting PMU mode and flags
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (11 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 12/23] x86/VPMU: Replace vcpu with vpmu as argument to some routines Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-30 13:31 ` Jan Beulich
2015-01-05 21:44 ` [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall Boris Ostrovsky
` (10 subsequent siblings)
23 siblings, 1 reply; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Add runtime interface for setting PMU mode and flags. Three main modes are
provided:
* XENPMU_MODE_OFF: PMU is not virtualized
* XENPMU_MODE_SELF: Guests can access PMU MSRs and receive PMU interrupts.
* XENPMU_MODE_HV: Same as XENPMU_MODE_SELF for non-proviledged guests, dom0
can profile itself and the hypervisor.
Note that PMU modes are different from what can be provided at Xen's boot line
with 'vpmu' argument. An 'off' (or '0') value is equivalent to XENPMU_MODE_OFF.
Any other value, on the other hand, will cause VPMU mode to be set to
XENPMU_MODE_SELF during boot.
For feature flags only Intel's BTS is currently supported.
Mode and flags are set via HYPERVISOR_xenpmu_op hypercall.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
tools/flask/policy/policy/modules/xen/xen.te | 3 +
xen/arch/x86/domain.c | 6 +-
xen/arch/x86/hvm/svm/vpmu.c | 25 +++-
xen/arch/x86/hvm/vmx/vmcs.c | 7 +-
xen/arch/x86/hvm/vmx/vpmu_core2.c | 27 +++-
xen/arch/x86/hvm/vpmu.c | 210 ++++++++++++++++++++++++++-
xen/arch/x86/oprofile/nmi_int.c | 3 +-
xen/arch/x86/x86_64/compat/entry.S | 4 +
xen/arch/x86/x86_64/entry.S | 4 +
xen/include/asm-x86/hvm/vmx/vmcs.h | 7 +-
xen/include/asm-x86/hvm/vpmu.h | 33 +++--
xen/include/public/pmu.h | 45 ++++++
xen/include/public/xen.h | 1 +
xen/include/xen/hypercall.h | 4 +
xen/include/xlat.lst | 1 +
xen/include/xsm/dummy.h | 15 ++
xen/include/xsm/xsm.h | 6 +
xen/xsm/dummy.c | 1 +
xen/xsm/flask/hooks.c | 18 +++
xen/xsm/flask/policy/access_vectors | 2 +
20 files changed, 390 insertions(+), 32 deletions(-)
diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te
index c0128aa..870ff81 100644
--- a/tools/flask/policy/policy/modules/xen/xen.te
+++ b/tools/flask/policy/policy/modules/xen/xen.te
@@ -68,6 +68,9 @@ allow dom0_t xen_t:xen2 {
resource_op
psr_cmt_op
};
+allow dom0_t xen_t:xen2 {
+ pmu_ctrl
+};
allow dom0_t xen_t:mmu memorymap;
# Allow dom0 to use these domctls on itself. For domctls acting on other
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 4e45fa8..d00622d 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1544,7 +1544,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
if ( is_hvm_vcpu(prev) )
{
if (prev != next)
- vpmu_save(vcpu_vpmu(prev));
+ vpmu_switch_from(vcpu_vpmu(prev), vcpu_vpmu(next));
if ( !list_empty(&prev->arch.hvm_vcpu.tm_list) )
pt_save_timer(prev);
@@ -1587,9 +1587,9 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
!is_hardware_domain(next->domain));
}
- if (is_hvm_vcpu(next) && (prev != next) )
+ if ( is_hvm_vcpu(next) && (prev != next) )
/* Must be done with interrupts enabled */
- vpmu_load(vcpu_vpmu(next));
+ vpmu_switch_to(vcpu_vpmu(prev), vcpu_vpmu(next));
context_saved(prev);
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 72e2561..2cfdf08 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -253,6 +253,26 @@ static int amd_vpmu_save(struct vpmu_struct *vpmu)
return 1;
}
+static void amd_vpmu_unload(struct vpmu_struct *vpmu)
+{
+ struct vcpu *v;
+
+ if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED | VPMU_FROZEN) )
+ {
+ unsigned int i;
+
+ for ( i = 0; i < num_counters; i++ )
+ wrmsrl(ctrls[i], 0);
+ context_save(vpmu);
+ }
+
+ v = vpmu_vcpu(vpmu);
+ if ( has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
+ amd_vpmu_unset_msr_bitmap(v);
+
+ vpmu_reset(vpmu, VPMU_FROZEN);
+}
+
static void context_update(unsigned int msr, u64 msr_content)
{
unsigned int i;
@@ -471,17 +491,18 @@ struct arch_vpmu_ops amd_vpmu_ops = {
.arch_vpmu_destroy = amd_vpmu_destroy,
.arch_vpmu_save = amd_vpmu_save,
.arch_vpmu_load = amd_vpmu_load,
+ .arch_vpmu_unload = amd_vpmu_unload,
.arch_vpmu_dump = amd_vpmu_dump
};
-int svm_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
+int svm_vpmu_initialise(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
uint8_t family = current_cpu_data.x86;
int ret = 0;
/* vpmu enabled? */
- if ( !vpmu_flags )
+ if ( vpmu_mode == XENPMU_MODE_OFF )
return 0;
switch ( family )
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index b9e3ef8..f45ce93 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1183,11 +1183,10 @@ int vmx_read_guest_msr(u32 msr, u64 *val)
return -ESRCH;
}
-int vmx_write_guest_msr(u32 msr, u64 val)
+int vmx_write_guest_msr_vcpu(struct vcpu *v, u32 msr, u64 val)
{
- struct vcpu *curr = current;
- unsigned int i, msr_count = curr->arch.hvm_vmx.msr_count;
- struct vmx_msr_entry *msr_area = curr->arch.hvm_vmx.msr_area;
+ unsigned int i, msr_count = v->arch.hvm_vmx.msr_count;
+ struct vmx_msr_entry *msr_area = v->arch.hvm_vmx.msr_area;
for ( i = 0; i < msr_count; i++ )
{
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index ad7c058..4d08d1b 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -320,6 +320,22 @@ static int core2_vpmu_save(struct vpmu_struct *vpmu)
return 1;
}
+static void core2_vpmu_unload(struct vpmu_struct *vpmu)
+{
+ struct vcpu *v = vpmu_vcpu(vpmu);
+
+ if ( !has_hvm_container_vcpu(v) )
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+ else
+ vmx_write_guest_msr_vcpu(v, MSR_CORE_PERF_GLOBAL_CTRL, 0);
+
+ if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
+ __core2_vpmu_save(vpmu);
+
+ if ( has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
+ core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
+}
+
static inline void __core2_vpmu_load(struct vpmu_struct *vpmu)
{
unsigned int i, pmc_start;
@@ -708,13 +724,13 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
return 1;
}
-static int core2_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
+static int core2_vpmu_initialise(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
u64 msr_content;
static bool_t ds_warned;
- if ( !(vpmu_flags & VPMU_BOOT_BTS) )
+ if ( !(vpmu_features & XENPMU_FEATURE_INTEL_BTS) )
goto func_out;
/* Check the 'Debug Store' feature in the CPUID.EAX[1]:EDX[21] */
while ( boot_cpu_has(X86_FEATURE_DS) )
@@ -784,6 +800,7 @@ struct arch_vpmu_ops core2_vpmu_ops = {
.arch_vpmu_destroy = core2_vpmu_destroy,
.arch_vpmu_save = core2_vpmu_save,
.arch_vpmu_load = core2_vpmu_load,
+ .arch_vpmu_unload = core2_vpmu_unload,
.arch_vpmu_dump = core2_vpmu_dump
};
@@ -826,7 +843,7 @@ struct arch_vpmu_ops core2_no_vpmu_ops = {
.do_cpuid = core2_no_vpmu_do_cpuid,
};
-int vmx_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
+int vmx_vpmu_initialise(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
uint8_t family = current_cpu_data.x86;
@@ -834,7 +851,7 @@ int vmx_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
int ret = 0;
vpmu->arch_vpmu_ops = &core2_no_vpmu_ops;
- if ( !vpmu_flags )
+ if ( vpmu_mode == XENPMU_MODE_OFF )
return 0;
if ( family == 6 )
@@ -877,7 +894,7 @@ int vmx_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
/* future: */
case 0x3d:
case 0x4e:
- ret = core2_vpmu_initialise(v, vpmu_flags);
+ ret = core2_vpmu_initialise(v);
if ( !ret )
vpmu->arch_vpmu_ops = &core2_vpmu_ops;
return ret;
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 752ae0d..4ce6513 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -21,6 +21,8 @@
#include <xen/config.h>
#include <xen/sched.h>
#include <xen/xenoprof.h>
+#include <xen/event.h>
+#include <xen/guest_access.h>
#include <asm/regs.h>
#include <asm/types.h>
#include <asm/msr.h>
@@ -32,8 +34,10 @@
#include <asm/hvm/svm/vmcb.h>
#include <asm/apic.h>
#include <public/pmu.h>
+#include <xsm/xsm.h>
#include <compat/pmu.h>
+CHECK_pmu_params;
CHECK_pmu_intel_ctxt;
CHECK_pmu_amd_ctxt;
CHECK_pmu_cntr_pair;
@@ -44,7 +48,8 @@ CHECK_pmu_regs;
* "vpmu=off" : vpmu generally disabled
* "vpmu=bts" : vpmu enabled and Intel BTS feature switched on.
*/
-static unsigned int __read_mostly opt_vpmu_enabled;
+unsigned int __read_mostly vpmu_mode = XENPMU_MODE_OFF;
+unsigned int __read_mostly vpmu_features = 0;
static void parse_vpmu_param(char *s);
custom_param("vpmu", parse_vpmu_param);
@@ -58,7 +63,7 @@ static void __init parse_vpmu_param(char *s)
break;
default:
if ( !strcmp(s, "bts") )
- opt_vpmu_enabled |= VPMU_BOOT_BTS;
+ vpmu_features |= XENPMU_FEATURE_INTEL_BTS;
else if ( *s )
{
printk("VPMU: unknown flag: %s - vpmu disabled!\n", s);
@@ -66,7 +71,8 @@ static void __init parse_vpmu_param(char *s)
}
/* fall through */
case 1:
- opt_vpmu_enabled |= VPMU_BOOT_ENABLED;
+ /* Default VPMU mode */
+ vpmu_mode = XENPMU_MODE_SELF;
break;
}
}
@@ -83,6 +89,9 @@ int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported)
{
struct vpmu_struct *vpmu = vcpu_vpmu(current);
+ if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
+ return 0;
+
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_wrmsr )
return vpmu->arch_vpmu_ops->do_wrmsr(msr, msr_content, supported);
return 0;
@@ -92,6 +101,12 @@ int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
{
struct vpmu_struct *vpmu = vcpu_vpmu(current);
+ if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
+ {
+ *msr_content = 0;
+ return 0;
+ }
+
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_rdmsr )
return vpmu->arch_vpmu_ops->do_rdmsr(msr, msr_content);
return 0;
@@ -243,19 +258,19 @@ void vpmu_initialise(struct vcpu *v)
switch ( vendor )
{
case X86_VENDOR_AMD:
- ret = svm_vpmu_initialise(v, opt_vpmu_enabled);
+ ret = svm_vpmu_initialise(v);
break;
case X86_VENDOR_INTEL:
- ret = vmx_vpmu_initialise(v, opt_vpmu_enabled);
+ ret = vmx_vpmu_initialise(v);
break;
default:
- if ( opt_vpmu_enabled )
+ if ( vpmu_mode != XENPMU_MODE_OFF )
{
printk(XENLOG_G_WARNING "VPMU: Unknown CPU vendor %d. "
"Disabling VPMU\n", vendor);
- opt_vpmu_enabled = 0;
+ vpmu_mode = XENPMU_MODE_OFF;
}
return;
}
@@ -301,3 +316,184 @@ void vpmu_dump(struct vcpu *v)
vpmu->arch_vpmu_ops->arch_vpmu_dump(v);
}
+void vpmu_unload(struct vpmu_struct *vpmu)
+{
+ if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED | VPMU_RUNNING) )
+ return;
+
+ if (vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_unload)
+ vpmu->arch_vpmu_ops->arch_vpmu_unload(vpmu);
+
+ vpmu_reset(vpmu, VPMU_CONTEXT_LOADED | VPMU_RUNNING);
+}
+
+#define VPMU_INVALID_CPU (~0U)
+static unsigned int vpmu_first_unload_cpu = VPMU_INVALID_CPU;
+static unsigned int vpmu_next_unload_cpu;
+
+static long vpmu_unload_next(void *arg)
+{
+ struct vcpu *last;
+ int ret;
+ unsigned int thiscpu = smp_processor_id();
+
+ if ( thiscpu != vpmu_next_unload_cpu )
+ {
+ /* Continuation thread may have been moved due to CPU hot-unplug */
+ vpmu_mode = (unsigned long)arg;
+ vpmu_first_unload_cpu = VPMU_INVALID_CPU;
+ return -EAGAIN;
+ }
+
+ local_irq_disable(); /* so that last_vcpu doesn't change under us. */
+
+ last = this_cpu(last_vcpu);
+ if ( last )
+ {
+ vpmu_unload(vcpu_vpmu(last));
+ this_cpu(last_vcpu) = NULL;
+ }
+
+ local_irq_enable();
+
+ vpmu_next_unload_cpu = cpumask_cycle(thiscpu, &cpu_online_map);
+ if ( vpmu_next_unload_cpu == vpmu_first_unload_cpu )
+ {
+ /* We have visited everyone. */
+ vpmu_first_unload_cpu = VPMU_INVALID_CPU;
+ return 0;
+ }
+
+ while ( !cpumask_test_cpu(vpmu_first_unload_cpu, &cpu_online_map) )
+ {
+ /* First cpu was hot-unplugged */
+ vpmu_first_unload_cpu = cpumask_cycle(vpmu_first_unload_cpu,
+ &cpu_online_map);
+ if ( thiscpu == vpmu_first_unload_cpu )
+ {
+ vpmu_first_unload_cpu = VPMU_INVALID_CPU;
+ return 0;
+ }
+ }
+
+ ret = continue_hypercall_on_cpu(vpmu_next_unload_cpu,
+ vpmu_unload_next, arg);
+ if ( ret )
+ {
+ vpmu_mode = (unsigned long)arg;
+ vpmu_first_unload_cpu = VPMU_INVALID_CPU;
+ }
+
+ return ret;
+}
+
+static int vpmu_unload_all(unsigned long old_mode)
+{
+ int ret = 0;
+
+ vpmu_unload(vcpu_vpmu(current));
+
+ if ( cpumask_weight(&cpu_online_map) > 1 )
+ {
+ unsigned int thiscpu = smp_processor_id();
+
+ vpmu_first_unload_cpu = thiscpu;
+ vpmu_next_unload_cpu = cpumask_cycle(thiscpu, &cpu_online_map);
+
+ ret = continue_hypercall_on_cpu(vpmu_next_unload_cpu, vpmu_unload_next,
+ (void *)old_mode);
+ if ( ret )
+ vpmu_first_unload_cpu = VPMU_INVALID_CPU;
+ }
+
+ return ret;
+}
+
+long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
+{
+ int ret;
+ struct xen_pmu_params pmu_params;
+
+ ret = xsm_pmu_op(XSM_OTHER, current->domain, op);
+ if ( ret )
+ return ret;
+
+ switch ( op )
+ {
+ case XENPMU_mode_set:
+ {
+ unsigned int old_mode;
+ static DEFINE_SPINLOCK(xenpmu_mode_lock);
+
+ if ( copy_from_guest(&pmu_params, arg, 1) )
+ return -EFAULT;
+
+ if ( pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV) )
+ return -EINVAL;
+
+ /* 32-bit dom0 can only sample itself. */
+ if ( is_pv_32bit_vcpu(current) && (pmu_params.val & XENPMU_MODE_HV) )
+ return -EINVAL;
+
+ /*
+ * Return error if someone else is in the middle of changing mode ---
+ * this is most likely indication of two system administrators
+ * working against each other.
+ */
+ if ( !spin_trylock(&xenpmu_mode_lock) )
+ return -EAGAIN;
+ if ( vpmu_first_unload_cpu != VPMU_INVALID_CPU )
+ {
+ spin_unlock(&xenpmu_mode_lock);
+ return -EAGAIN;
+ }
+
+ old_mode = vpmu_mode;
+ vpmu_mode = pmu_params.val;
+
+ if ( vpmu_mode == XENPMU_MODE_OFF )
+ {
+ /* Make sure all (non-dom0) VCPUs have unloaded their VPMUs. */
+ ret = vpmu_unload_all(old_mode);
+ if ( ret )
+ vpmu_mode = old_mode;
+ }
+
+ spin_unlock(&xenpmu_mode_lock);
+
+ break;
+ }
+
+ case XENPMU_mode_get:
+ memset(&pmu_params, 0, sizeof(pmu_params));
+ pmu_params.val = vpmu_mode;
+
+ pmu_params.version.maj = XENPMU_VER_MAJ;
+ pmu_params.version.min = XENPMU_VER_MIN;
+
+ if ( copy_to_guest(arg, &pmu_params, 1) )
+ return -EFAULT;
+ break;
+
+ case XENPMU_feature_set:
+ if ( copy_from_guest(&pmu_params, arg, 1) )
+ return -EFAULT;
+
+ if ( pmu_params.val & ~XENPMU_FEATURE_INTEL_BTS )
+ return -EINVAL;
+
+ vpmu_features = pmu_params.val;
+ break;
+
+ case XENPMU_feature_get:
+ pmu_params.val = vpmu_features;
+ if ( copy_field_to_guest(arg, &pmu_params, val) )
+ return -EFAULT;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/xen/arch/x86/oprofile/nmi_int.c b/xen/arch/x86/oprofile/nmi_int.c
index 13534d4..3c3a37c 100644
--- a/xen/arch/x86/oprofile/nmi_int.c
+++ b/xen/arch/x86/oprofile/nmi_int.c
@@ -47,7 +47,8 @@ static int passive_domain_msr_op_checks(unsigned int msr, int *typep, int *index
if ( !model->is_arch_pmu_msr(msr, typep, indexp) )
return 0;
- if ( !vpmu_is_set(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED) )
+ if ( !vpmu_is_set(vpmu, VPMU_PASSIVE_DOMAIN_ALLOCATED |
+ VPMU_CONTEXT_ALLOCATED) )
if ( ! model->allocated_msr(current) )
return 0;
return 1;
diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S
index 5b0af61..7691a79 100644
--- a/xen/arch/x86/x86_64/compat/entry.S
+++ b/xen/arch/x86/x86_64/compat/entry.S
@@ -417,6 +417,8 @@ ENTRY(compat_hypercall_table)
.quad do_domctl
.quad compat_kexec_op
.quad do_tmem_op
+ .quad do_ni_hypercall /* reserved for XenClient */
+ .quad do_xenpmu_op /* 40 */
.rept __HYPERVISOR_arch_0-((.-compat_hypercall_table)/8)
.quad compat_ni_hypercall
.endr
@@ -466,6 +468,8 @@ ENTRY(compat_hypercall_args_table)
.byte 1 /* do_domctl */
.byte 2 /* compat_kexec_op */
.byte 1 /* do_tmem_op */
+ .byte 0 /* reserved for XenClient */
+ .byte 2 /* do_xenpmu_op */ /* 40 */
.rept __HYPERVISOR_arch_0-(.-compat_hypercall_args_table)
.byte 0 /* compat_ni_hypercall */
.endr
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index b3d6e32..aa842ac 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -772,6 +772,8 @@ ENTRY(hypercall_table)
.quad do_domctl
.quad do_kexec_op
.quad do_tmem_op
+ .quad do_ni_hypercall /* reserved for XenClient */
+ .quad do_xenpmu_op /* 40 */
.rept __HYPERVISOR_arch_0-((.-hypercall_table)/8)
.quad do_ni_hypercall
.endr
@@ -821,6 +823,8 @@ ENTRY(hypercall_args_table)
.byte 1 /* do_domctl */
.byte 2 /* do_kexec */
.byte 1 /* do_tmem_op */
+ .byte 0 /* reserved for XenClient */
+ .byte 2 /* do_xenpmu_op */ /* 40 */
.rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 949884b..5407379 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -489,7 +489,7 @@ extern const unsigned int vmx_introspection_force_enabled_msrs_size;
void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type);
void vmx_enable_intercept_for_msr(struct vcpu *v, u32 msr, int type);
int vmx_read_guest_msr(u32 msr, u64 *val);
-int vmx_write_guest_msr(u32 msr, u64 val);
+int vmx_write_guest_msr_vcpu(struct vcpu *v, u32 msr, u64 val);
int vmx_add_msr(u32 msr, int type);
void vmx_vmcs_switch(struct vmcs_struct *from, struct vmcs_struct *to);
void vmx_set_eoi_exit_bitmap(struct vcpu *v, u8 vector);
@@ -509,6 +509,11 @@ static inline int vmx_add_host_load_msr(u32 msr)
return vmx_add_msr(msr, VMX_HOST_MSR);
}
+static inline int vmx_write_guest_msr(u32 msr, u64 val)
+{
+ return vmx_write_guest_msr_vcpu(current, msr, val);
+}
+
DECLARE_PER_CPU(bool_t, vmxon);
#endif /* ASM_X86_HVM_VMX_VMCS_H__ */
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 897d5de..1171b2a 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -24,13 +24,6 @@
#include <public/pmu.h>
-/*
- * Flag bits given as a string on the hypervisor boot parameter 'vpmu'.
- * See arch/x86/hvm/vpmu.c.
- */
-#define VPMU_BOOT_ENABLED 0x1 /* vpmu generally enabled. */
-#define VPMU_BOOT_BTS 0x2 /* Intel BTS feature wanted. */
-
#define vcpu_vpmu(vcpu) (&(vcpu)->arch.vpmu)
#define vpmu_vcpu(vpmu) container_of((vpmu), struct vcpu, arch.vpmu)
@@ -65,11 +58,12 @@ struct arch_vpmu_ops {
void (*arch_vpmu_destroy)(struct vcpu *v);
int (*arch_vpmu_save)(struct vpmu_struct *vpmu);
void (*arch_vpmu_load)(struct vpmu_struct *vpmu);
+ void (*arch_vpmu_unload)(struct vpmu_struct *vpmu);
void (*arch_vpmu_dump)(const struct vcpu *);
};
-int vmx_vpmu_initialise(struct vcpu *, unsigned int flags);
-int svm_vpmu_initialise(struct vcpu *, unsigned int flags);
+int vmx_vpmu_initialise(struct vcpu *);
+int svm_vpmu_initialise(struct vcpu *);
/* VPMU states */
#define VPMU_CONTEXT_ALLOCATED 0x1
@@ -111,10 +105,31 @@ void vpmu_initialise(struct vcpu *v);
void vpmu_destroy(struct vcpu *v);
void vpmu_save(struct vpmu_struct *vpmu);
void vpmu_load(struct vpmu_struct *vpmu);
+void vpmu_unload(struct vpmu_struct *vpmu);
void vpmu_dump(struct vcpu *v);
extern int acquire_pmu_ownership(int pmu_ownership);
extern void release_pmu_ownership(int pmu_ownership);
+extern unsigned int vpmu_mode;
+extern unsigned int vpmu_features;
+
+/* Context switch */
+static inline void vpmu_switch_from(struct vpmu_struct *prev,
+ struct vpmu_struct *next)
+{
+ if ( vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV) )
+ vpmu_save(prev);
+}
+
+static inline void vpmu_switch_to(struct vpmu_struct *prev,
+ struct vpmu_struct *next)
+{
+ if ( vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV) )
+ vpmu_load(next);
+ else if ( vpmu_is_set(next, VPMU_CONTEXT_LOADED | VPMU_RUNNING) )
+ vpmu_unload(next);
+}
+
#endif /* __ASM_X86_HVM_VPMU_H_*/
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index f97106d..66cc494 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -13,6 +13,51 @@
#define XENPMU_VER_MAJ 0
#define XENPMU_VER_MIN 1
+/*
+ * ` enum neg_errnoval
+ * ` HYPERVISOR_xenpmu_op(enum xenpmu_op cmd, struct xenpmu_params *args);
+ *
+ * @cmd == XENPMU_* (PMU operation)
+ * @args == struct xenpmu_params
+ */
+/* ` enum xenpmu_op { */
+#define XENPMU_mode_get 0 /* Also used for getting PMU version */
+#define XENPMU_mode_set 1
+#define XENPMU_feature_get 2
+#define XENPMU_feature_set 3
+/* ` } */
+
+/* Parameters structure for HYPERVISOR_xenpmu_op call */
+struct xen_pmu_params {
+ /* IN/OUT parameters */
+ struct {
+ uint32_t maj;
+ uint32_t min;
+ } version;
+ uint64_t val;
+
+ /* IN parameters */
+ uint32_t vcpu;
+ uint32_t pad;
+};
+typedef struct xen_pmu_params xen_pmu_params_t;
+DEFINE_XEN_GUEST_HANDLE(xen_pmu_params_t);
+
+/* PMU modes:
+ * - XENPMU_MODE_OFF: No PMU virtualization
+ * - XENPMU_MODE_SELF: Guests can profile themselves
+ * - XENPMU_MODE_HV: Guests can profile themselves, dom0 profiles
+ * itself and Xen
+ */
+#define XENPMU_MODE_OFF 0
+#define XENPMU_MODE_SELF (1<<0)
+#define XENPMU_MODE_HV (1<<1)
+
+/*
+ * PMU features:
+ * - XENPMU_FEATURE_INTEL_BTS: Intel BTS support (ignored on AMD)
+ */
+#define XENPMU_FEATURE_INTEL_BTS 1
/* Shared between hypervisor and PV domain */
struct xen_pmu_data {
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index a6a2092..0766790 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -101,6 +101,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
#define __HYPERVISOR_kexec_op 37
#define __HYPERVISOR_tmem_op 38
#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
+#define __HYPERVISOR_xenpmu_op 40
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h
index 8c55779..8da3dd8 100644
--- a/xen/include/xen/hypercall.h
+++ b/xen/include/xen/hypercall.h
@@ -14,6 +14,7 @@
#include <public/event_channel.h>
#include <public/tmem.h>
#include <public/version.h>
+#include <public/pmu.h>
#include <asm/hypercall.h>
#include <xsm/xsm.h>
@@ -144,6 +145,9 @@ do_tmem_op(
extern long
do_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg);
+extern long
+do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg);
+
#ifdef CONFIG_COMPAT
extern int
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index b6bef8c..f6f02e1 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -107,6 +107,7 @@
? pmu_cntr_pair arch-x86/pmu.h
? pmu_intel_ctxt arch-x86/pmu.h
? pmu_regs arch-x86/pmu.h
+? pmu_params pmu.h
? flask_access xsm/flask_op.h
! flask_boolean xsm/flask_op.h
? flask_cache_stats xsm/flask_op.h
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index f20e89c..c637454 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -655,4 +655,19 @@ static XSM_INLINE int xsm_ioport_mapping(XSM_DEFAULT_ARG struct domain *d, uint3
return xsm_default_action(action, current->domain, d);
}
+static XSM_INLINE int xsm_pmu_op (XSM_DEFAULT_ARG struct domain *d, int op)
+{
+ XSM_ASSERT_ACTION(XSM_OTHER);
+ switch ( op )
+ {
+ case XENPMU_mode_set:
+ case XENPMU_mode_get:
+ case XENPMU_feature_set:
+ case XENPMU_feature_get:
+ return xsm_default_action(XSM_PRIV, d, current->domain);
+ default:
+ return -EPERM;
+ }
+}
+
#endif /* CONFIG_X86 */
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 4ce089f..0e39dfe 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -173,6 +173,7 @@ struct xsm_operations {
int (*unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind);
int (*ioport_permission) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow);
int (*ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow);
+ int (*pmu_op) (struct domain *d, int op);
#endif
};
@@ -665,6 +666,11 @@ static inline int xsm_ioport_mapping (xsm_default_t def, struct domain *d, uint3
return xsm_ops->ioport_mapping(d, s, e, allow);
}
+static inline int xsm_pmu_op (xsm_default_t def, struct domain *d, int op)
+{
+ return xsm_ops->pmu_op(d, op);
+}
+
#endif /* CONFIG_X86 */
#endif /* XSM_NO_WRAPPERS */
diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index 8eb3050..94f1cf0 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -144,5 +144,6 @@ void xsm_fixup_ops (struct xsm_operations *ops)
set_to_dummy_if_null(ops, unbind_pt_irq);
set_to_dummy_if_null(ops, ioport_permission);
set_to_dummy_if_null(ops, ioport_mapping);
+ set_to_dummy_if_null(ops, pmu_op);
#endif
}
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index c589e49..a24c480 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -1504,6 +1504,23 @@ static int flask_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq
{
return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE);
}
+
+static int flask_pmu_op (struct domain *d, int op)
+{
+ u32 dsid = domain_sid(d);
+
+ switch ( op )
+ {
+ case XENPMU_mode_set:
+ case XENPMU_mode_get:
+ case XENPMU_feature_set:
+ case XENPMU_feature_get:
+ return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_XEN2,
+ XEN2__PMU_CTRL, NULL);
+ default:
+ return -EPERM;
+ }
+}
#endif /* CONFIG_X86 */
long do_flask_op(XEN_GUEST_HANDLE_PARAM(xsm_op_t) u_flask_op);
@@ -1626,6 +1643,7 @@ static struct xsm_operations flask_ops = {
.unbind_pt_irq = flask_unbind_pt_irq,
.ioport_permission = flask_ioport_permission,
.ioport_mapping = flask_ioport_mapping,
+ .pmu_op = flask_pmu_op,
#endif
};
diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors
index ed91c09..4786a39 100644
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -85,6 +85,8 @@ class xen2
psr_cmt_op
# XENPF_get_symbol
get_symbol
+# PMU control
+ pmu_ctrl
}
# Classes domain and domain2 consist of operations that a domain performs on
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v17 13/23] x86/VPMU: Interface for setting PMU mode and flags
2015-01-05 21:44 ` [PATCH v17 13/23] x86/VPMU: Interface for setting PMU mode and flags Boris Ostrovsky
@ 2015-01-30 13:31 ` Jan Beulich
2015-01-30 15:17 ` Boris Ostrovsky
0 siblings, 1 reply; 31+ messages in thread
From: Jan Beulich @ 2015-01-30 13:31 UTC (permalink / raw)
To: Boris Ostrovsky
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
>>> On 05.01.15 at 22:44, <boris.ostrovsky@oracle.com> wrote:
> +static long vpmu_unload_next(void *arg)
> +{
> + struct vcpu *last;
> + int ret;
> + unsigned int thiscpu = smp_processor_id();
> +
> + if ( thiscpu != vpmu_next_unload_cpu )
> + {
> + /* Continuation thread may have been moved due to CPU hot-unplug */
> + vpmu_mode = (unsigned long)arg;
> + vpmu_first_unload_cpu = VPMU_INVALID_CPU;
> + return -EAGAIN;
> + }
> +
> + local_irq_disable(); /* so that last_vcpu doesn't change under us. */
> +
> + last = this_cpu(last_vcpu);
> + if ( last )
> + {
> + vpmu_unload(vcpu_vpmu(last));
> + this_cpu(last_vcpu) = NULL;
> + }
So you do this for last_vcpu here, but ...
> +static int vpmu_unload_all(unsigned long old_mode)
> +{
> + int ret = 0;
> +
> + vpmu_unload(vcpu_vpmu(current));
... for current here, also without clearing this_cpu(last_vcpu). Is
that really correct?
> +long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
> +{
> + int ret;
> + struct xen_pmu_params pmu_params;
> +
> + ret = xsm_pmu_op(XSM_OTHER, current->domain, op);
> + if ( ret )
> + return ret;
> +
> + switch ( op )
> + {
> + case XENPMU_mode_set:
> + {
> + unsigned int old_mode;
> + static DEFINE_SPINLOCK(xenpmu_mode_lock);
> +
> + if ( copy_from_guest(&pmu_params, arg, 1) )
> + return -EFAULT;
> +
> + if ( pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV) )
> + return -EINVAL;
> +
> + /* 32-bit dom0 can only sample itself. */
> + if ( is_pv_32bit_vcpu(current) && (pmu_params.val & XENPMU_MODE_HV) )
> + return -EINVAL;
> +
> + /*
> + * Return error if someone else is in the middle of changing mode ---
> + * this is most likely indication of two system administrators
> + * working against each other.
> + */
> + if ( !spin_trylock(&xenpmu_mode_lock) )
> + return -EAGAIN;
> + if ( vpmu_first_unload_cpu != VPMU_INVALID_CPU )
> + {
> + spin_unlock(&xenpmu_mode_lock);
> + return -EAGAIN;
> + }
> +
> + old_mode = vpmu_mode;
> + vpmu_mode = pmu_params.val;
> +
> + if ( vpmu_mode == XENPMU_MODE_OFF )
> + {
> + /* Make sure all (non-dom0) VCPUs have unloaded their VPMUs. */
> + ret = vpmu_unload_all(old_mode);
> + if ( ret )
> + vpmu_mode = old_mode;
> + }
> +
> + spin_unlock(&xenpmu_mode_lock);
> +
> + break;
> + }
> +
> + case XENPMU_mode_get:
> + memset(&pmu_params, 0, sizeof(pmu_params));
> + pmu_params.val = vpmu_mode;
> +
> + pmu_params.version.maj = XENPMU_VER_MAJ;
> + pmu_params.version.min = XENPMU_VER_MIN;
> +
> + if ( copy_to_guest(arg, &pmu_params, 1) )
> + return -EFAULT;
> + break;
> +
> + case XENPMU_feature_set:
> + if ( copy_from_guest(&pmu_params, arg, 1) )
> + return -EFAULT;
> +
> + if ( pmu_params.val & ~XENPMU_FEATURE_INTEL_BTS )
> + return -EINVAL;
> +
> + vpmu_features = pmu_params.val;
> + break;
> +
> + case XENPMU_feature_get:
> + pmu_params.val = vpmu_features;
> + if ( copy_field_to_guest(arg, &pmu_params, val) )
> + return -EFAULT;
> + break;
> +
> + default:
> + ret = -EINVAL;
> + }
> +
> + return ret;
> +}
Throughout this function, the "pad" field isn't being checked to be
zero (and XENPMU_feature_get also doesn't clear it, but that seems
secondary, at least as long as it's being declared "IN" only). As I'm
sure I said before - we ought to do this in order to be able to assign
meaning to the field later on. Perhaps it would even better be
renamed to e.g. "mbz".
> @@ -144,6 +145,9 @@ do_tmem_op(
> extern long
> do_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg);
>
> +extern long
> +do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg);
Despite there being numerous bad examples - can "op" please be
"unsigned int"?
> --- a/xen/include/xsm/xsm.h
> +++ b/xen/include/xsm/xsm.h
> @@ -173,6 +173,7 @@ struct xsm_operations {
> int (*unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind);
> int (*ioport_permission) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow);
> int (*ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow);
> + int (*pmu_op) (struct domain *d, int op);
And then here too?
Jan
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v17 13/23] x86/VPMU: Interface for setting PMU mode and flags
2015-01-30 13:31 ` Jan Beulich
@ 2015-01-30 15:17 ` Boris Ostrovsky
0 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-30 15:17 UTC (permalink / raw)
To: Jan Beulich
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
On 01/30/2015 08:31 AM, Jan Beulich wrote:
>>>> On 05.01.15 at 22:44, <boris.ostrovsky@oracle.com> wrote:
>> +static long vpmu_unload_next(void *arg)
>> +{
>> + struct vcpu *last;
>> + int ret;
>> + unsigned int thiscpu = smp_processor_id();
>> +
>> + if ( thiscpu != vpmu_next_unload_cpu )
>> + {
>> + /* Continuation thread may have been moved due to CPU hot-unplug */
>> + vpmu_mode = (unsigned long)arg;
>> + vpmu_first_unload_cpu = VPMU_INVALID_CPU;
>> + return -EAGAIN;
>> + }
>> +
>> + local_irq_disable(); /* so that last_vcpu doesn't change under us. */
>> +
>> + last = this_cpu(last_vcpu);
>> + if ( last )
>> + {
>> + vpmu_unload(vcpu_vpmu(last));
>> + this_cpu(last_vcpu) = NULL;
>> + }
> So you do this for last_vcpu here, but ...
>
>
>> +static int vpmu_unload_all(unsigned long old_mode)
>> +{
>> + int ret = 0;
>> +
>> + vpmu_unload(vcpu_vpmu(current));
> ... for current here, also without clearing this_cpu(last_vcpu). Is
> that really correct?
No, I should clear it here as well.
>
>> +long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
>> +{
>> + int ret;
>> + struct xen_pmu_params pmu_params;
>> +
>> + ret = xsm_pmu_op(XSM_OTHER, current->domain, op);
>> + if ( ret )
>> + return ret;
>> +
>> + switch ( op )
>> + {
>> + case XENPMU_mode_set:
>> + {
>> + unsigned int old_mode;
>> + static DEFINE_SPINLOCK(xenpmu_mode_lock);
>> +
>> + if ( copy_from_guest(&pmu_params, arg, 1) )
>> + return -EFAULT;
>> +
>> + if ( pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV) )
>> + return -EINVAL;
>> +
>> + /* 32-bit dom0 can only sample itself. */
>> + if ( is_pv_32bit_vcpu(current) && (pmu_params.val & XENPMU_MODE_HV) )
>> + return -EINVAL;
>> +
>> + /*
>> + * Return error if someone else is in the middle of changing mode ---
>> + * this is most likely indication of two system administrators
>> + * working against each other.
>> + */
>> + if ( !spin_trylock(&xenpmu_mode_lock) )
>> + return -EAGAIN;
>> + if ( vpmu_first_unload_cpu != VPMU_INVALID_CPU )
>> + {
>> + spin_unlock(&xenpmu_mode_lock);
>> + return -EAGAIN;
>> + }
>> +
>> + old_mode = vpmu_mode;
>> + vpmu_mode = pmu_params.val;
>> +
>> + if ( vpmu_mode == XENPMU_MODE_OFF )
>> + {
>> + /* Make sure all (non-dom0) VCPUs have unloaded their VPMUs. */
>> + ret = vpmu_unload_all(old_mode);
>> + if ( ret )
>> + vpmu_mode = old_mode;
>> + }
>> +
>> + spin_unlock(&xenpmu_mode_lock);
>> +
>> + break;
>> + }
>> +
>> + case XENPMU_mode_get:
>> + memset(&pmu_params, 0, sizeof(pmu_params));
>> + pmu_params.val = vpmu_mode;
>> +
>> + pmu_params.version.maj = XENPMU_VER_MAJ;
>> + pmu_params.version.min = XENPMU_VER_MIN;
>> +
>> + if ( copy_to_guest(arg, &pmu_params, 1) )
>> + return -EFAULT;
>> + break;
>> +
>> + case XENPMU_feature_set:
>> + if ( copy_from_guest(&pmu_params, arg, 1) )
>> + return -EFAULT;
>> +
>> + if ( pmu_params.val & ~XENPMU_FEATURE_INTEL_BTS )
>> + return -EINVAL;
>> +
>> + vpmu_features = pmu_params.val;
>> + break;
>> +
>> + case XENPMU_feature_get:
>> + pmu_params.val = vpmu_features;
>> + if ( copy_field_to_guest(arg, &pmu_params, val) )
>> + return -EFAULT;
>> + break;
>> +
>> + default:
>> + ret = -EINVAL;
>> + }
>> +
>> + return ret;
>> +}
> Throughout this function, the "pad" field isn't being checked to be
> zero (and XENPMU_feature_get also doesn't clear it, but that seems
> secondary, at least as long as it's being declared "IN" only). As I'm
> sure I said before - we ought to do this in order to be able to assign
> meaning to the field later on. Perhaps it would even better be
> renamed to e.g. "mbz".
If we decide to start using this filed then presumably we will have to
bump interface version. If pad field becomes something else it will only
be considered when minor version is > 1. (And I should probably add
major version check.)
-boris
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (12 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 13/23] x86/VPMU: Interface for setting PMU mode and flags Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-30 14:54 ` Jan Beulich
2015-01-05 21:44 ` [PATCH v17 15/23] x86/VPMU: Initialize PMU for PV(H) guests Boris Ostrovsky
` (9 subsequent siblings)
23 siblings, 1 reply; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Move some VPMU initilization operations into __initcalls to avoid performing
same tests and calculations for each vcpu.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/svm/vpmu.c | 112 ++++++++++++----------------
xen/arch/x86/hvm/vmx/vpmu_core2.c | 151 +++++++++++++++++++-------------------
xen/arch/x86/hvm/vpmu.c | 36 +++++++++
xen/include/asm-x86/hvm/vpmu.h | 2 +
4 files changed, 161 insertions(+), 140 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 2cfdf08..03474a3 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -375,57 +375,6 @@ static int amd_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
return 1;
}
-static int amd_vpmu_initialise(struct vcpu *v)
-{
- struct xen_pmu_amd_ctxt *ctxt;
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
- uint8_t family = current_cpu_data.x86;
-
- if ( vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
- return 0;
-
- if ( counters == NULL )
- {
- switch ( family )
- {
- case 0x15:
- num_counters = F15H_NUM_COUNTERS;
- counters = AMD_F15H_COUNTERS;
- ctrls = AMD_F15H_CTRLS;
- k7_counters_mirrored = 1;
- break;
- case 0x10:
- case 0x12:
- case 0x14:
- case 0x16:
- default:
- num_counters = F10H_NUM_COUNTERS;
- counters = AMD_F10H_COUNTERS;
- ctrls = AMD_F10H_CTRLS;
- k7_counters_mirrored = 0;
- break;
- }
- }
-
- ctxt = xzalloc_bytes(sizeof(*ctxt) +
- 2 * sizeof(uint64_t) * num_counters);
- if ( !ctxt )
- {
- gdprintk(XENLOG_WARNING, "Insufficient memory for PMU, "
- " PMU feature is unavailable on domain %d vcpu %d.\n",
- v->vcpu_id, v->domain->domain_id);
- return -ENOMEM;
- }
-
- ctxt->counters = sizeof(*ctxt);
- ctxt->ctrls = ctxt->counters + sizeof(uint64_t) * num_counters;
-
- vpmu->context = ctxt;
- vpmu->priv_context = NULL;
- vpmu_set(vpmu, VPMU_CONTEXT_ALLOCATED);
- return 0;
-}
-
static void amd_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
@@ -497,30 +446,63 @@ struct arch_vpmu_ops amd_vpmu_ops = {
int svm_vpmu_initialise(struct vcpu *v)
{
+ struct xen_pmu_amd_ctxt *ctxt;
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- uint8_t family = current_cpu_data.x86;
- int ret = 0;
- /* vpmu enabled? */
- if ( vpmu_mode == XENPMU_MODE_OFF )
+ if ( (vpmu_mode == XENPMU_MODE_OFF) ||
+ vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
return 0;
- switch ( family )
+ if ( !counters )
+ return -EINVAL;
+
+ ctxt = xzalloc_bytes(sizeof(*ctxt) +
+ 2 * sizeof(uint64_t) * num_counters);
+ if ( !ctxt )
+ {
+ printk(XENLOG_G_WARNING "Insufficient memory for PMU, "
+ " PMU feature is unavailable on domain %d vcpu %d.\n",
+ v->vcpu_id, v->domain->domain_id);
+ return -ENOMEM;
+ }
+
+ ctxt->counters = sizeof(*ctxt);
+ ctxt->ctrls = ctxt->counters + sizeof(uint64_t) * num_counters;
+
+ vpmu->context = ctxt;
+ vpmu->priv_context = NULL;
+
+ vpmu->arch_vpmu_ops = &amd_vpmu_ops;
+
+ vpmu_set(vpmu, VPMU_CONTEXT_ALLOCATED);
+ return 0;
+}
+
+int __init amd_vpmu_init(void)
+{
+ switch ( current_cpu_data.x86 )
{
+ case 0x15:
+ num_counters = F15H_NUM_COUNTERS;
+ counters = AMD_F15H_COUNTERS;
+ ctrls = AMD_F15H_CTRLS;
+ k7_counters_mirrored = 1;
+ break;
case 0x10:
case 0x12:
case 0x14:
- case 0x15:
case 0x16:
- ret = amd_vpmu_initialise(v);
- if ( !ret )
- vpmu->arch_vpmu_ops = &amd_vpmu_ops;
- return ret;
+ num_counters = F10H_NUM_COUNTERS;
+ counters = AMD_F10H_COUNTERS;
+ ctrls = AMD_F10H_CTRLS;
+ k7_counters_mirrored = 0;
+ break;
+ default:
+ printk(XENLOG_WARNING "VPMU: Unsupported CPU family %#x\n",
+ current_cpu_data.x86);
+ return -EINVAL;
}
- printk("VPMU: Initialization failed. "
- "AMD processor family %d has not "
- "been supported\n", family);
- return -EINVAL;
+ return 0;
}
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 4d08d1b..6c78323 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -724,62 +724,6 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
return 1;
}
-static int core2_vpmu_initialise(struct vcpu *v)
-{
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
- u64 msr_content;
- static bool_t ds_warned;
-
- if ( !(vpmu_features & XENPMU_FEATURE_INTEL_BTS) )
- goto func_out;
- /* Check the 'Debug Store' feature in the CPUID.EAX[1]:EDX[21] */
- while ( boot_cpu_has(X86_FEATURE_DS) )
- {
- if ( !boot_cpu_has(X86_FEATURE_DTES64) )
- {
- if ( !ds_warned )
- printk(XENLOG_G_WARNING "CPU doesn't support 64-bit DS Area"
- " - Debug Store disabled for guests\n");
- break;
- }
- vpmu_set(vpmu, VPMU_CPU_HAS_DS);
- rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
- if ( msr_content & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL )
- {
- /* If BTS_UNAVAIL is set reset the DS feature. */
- vpmu_reset(vpmu, VPMU_CPU_HAS_DS);
- if ( !ds_warned )
- printk(XENLOG_G_WARNING "CPU has set BTS_UNAVAIL"
- " - Debug Store disabled for guests\n");
- break;
- }
-
- vpmu_set(vpmu, VPMU_CPU_HAS_BTS);
- if ( !ds_warned )
- {
- if ( !boot_cpu_has(X86_FEATURE_DSCPL) )
- printk(XENLOG_G_INFO
- "vpmu: CPU doesn't support CPL-Qualified BTS\n");
- printk("******************************************************\n");
- printk("** WARNING: Emulation of BTS Feature is switched on **\n");
- printk("** Using this processor feature in a virtualized **\n");
- printk("** environment is not 100%% safe. **\n");
- printk("** Setting the DS buffer address with wrong values **\n");
- printk("** may lead to hypervisor hangs or crashes. **\n");
- printk("** It is NOT recommended for production use! **\n");
- printk("******************************************************\n");
- }
- break;
- }
- ds_warned = 1;
- func_out:
-
- arch_pmc_cnt = core2_get_arch_pmc_count();
- fixed_pmc_cnt = core2_get_fixed_pmc_count();
- check_pmc_quirk();
- return 0;
-}
-
static void core2_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
@@ -846,23 +790,77 @@ struct arch_vpmu_ops core2_no_vpmu_ops = {
int vmx_vpmu_initialise(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- uint8_t family = current_cpu_data.x86;
- uint8_t cpu_model = current_cpu_data.x86_model;
- int ret = 0;
+ u64 msr_content;
+ static bool_t ds_warned;
vpmu->arch_vpmu_ops = &core2_no_vpmu_ops;
if ( vpmu_mode == XENPMU_MODE_OFF )
return 0;
- if ( family == 6 )
- {
- u64 caps;
+ if ( (arch_pmc_cnt + fixed_pmc_cnt) == 0 )
+ return -EINVAL;
- rdmsrl(MSR_IA32_PERF_CAPABILITIES, caps);
- full_width_write = (caps >> 13) & 1;
+ if ( !(vpmu_features & XENPMU_FEATURE_INTEL_BTS) )
+ goto func_out;
+ /* Check the 'Debug Store' feature in the CPUID.EAX[1]:EDX[21] */
+ while ( boot_cpu_has(X86_FEATURE_DS) )
+ {
+ if ( !boot_cpu_has(X86_FEATURE_DTES64) )
+ {
+ if ( !ds_warned )
+ printk(XENLOG_G_WARNING "CPU doesn't support 64-bit DS Area"
+ " - Debug Store disabled for guests\n");
+ break;
+ }
+ vpmu_set(vpmu, VPMU_CPU_HAS_DS);
+ rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
+ if ( msr_content & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL )
+ {
+ /* If BTS_UNAVAIL is set reset the DS feature. */
+ vpmu_reset(vpmu, VPMU_CPU_HAS_DS);
+ if ( !ds_warned )
+ printk(XENLOG_G_WARNING "CPU has set BTS_UNAVAIL"
+ " - Debug Store disabled for guests\n");
+ break;
+ }
- switch ( cpu_model )
+ vpmu_set(vpmu, VPMU_CPU_HAS_BTS);
+ if ( !ds_warned )
{
+ if ( !boot_cpu_has(X86_FEATURE_DSCPL) )
+ printk(XENLOG_G_INFO
+ "vpmu: CPU doesn't support CPL-Qualified BTS\n");
+ printk("******************************************************\n");
+ printk("** WARNING: Emulation of BTS Feature is switched on **\n");
+ printk("** Using this processor feature in a virtualized **\n");
+ printk("** environment is not 100%% safe. **\n");
+ printk("** Setting the DS buffer address with wrong values **\n");
+ printk("** may lead to hypervisor hangs or crashes. **\n");
+ printk("** It is NOT recommended for production use! **\n");
+ printk("******************************************************\n");
+ }
+ break;
+ }
+ ds_warned = 1;
+ func_out:
+
+ vpmu->arch_vpmu_ops = &core2_vpmu_ops;
+
+ return 0;
+}
+
+int __init core2_vpmu_init(void)
+{
+ u64 caps;
+
+ if ( current_cpu_data.x86 != 6 )
+ {
+ printk(XENLOG_WARNING "VPMU: only family 6 is supported\n");
+ return -EINVAL;
+ }
+
+ switch ( current_cpu_data.x86_model )
+ {
/* Core2: */
case 0x0f: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */
case 0x16: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */
@@ -894,16 +892,19 @@ int vmx_vpmu_initialise(struct vcpu *v)
/* future: */
case 0x3d:
case 0x4e:
- ret = core2_vpmu_initialise(v);
- if ( !ret )
- vpmu->arch_vpmu_ops = &core2_vpmu_ops;
- return ret;
- }
+ break;
+ default:
+ printk(XENLOG_WARNING "VPMU: Unsupported CPU model %#x\n",
+ current_cpu_data.x86_model);
+ return -EINVAL;
}
- printk("VPMU: Initialization failed. "
- "Intel processor family %d model %d has not "
- "been supported\n", family, cpu_model);
- return -EINVAL;
-}
+ arch_pmc_cnt = core2_get_arch_pmc_count();
+ fixed_pmc_cnt = core2_get_fixed_pmc_count();
+ rdmsrl(MSR_IA32_PERF_CAPABILITIES, caps);
+ full_width_write = (caps >> 13) & 1;
+ check_pmc_quirk();
+
+ return 0;
+}
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 4ce6513..fbce557 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -497,3 +497,39 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
return ret;
}
+
+static int __init vpmu_init(void)
+{
+ int vendor = current_cpu_data.x86_vendor;
+
+ if ( vpmu_mode == XENPMU_MODE_OFF )
+ {
+ printk(XENLOG_INFO "VPMU: disabled\n");
+ return 0;
+ }
+
+ switch ( vendor )
+ {
+ case X86_VENDOR_AMD:
+ if ( amd_vpmu_init() )
+ vpmu_mode = XENPMU_MODE_OFF;
+ break;
+ case X86_VENDOR_INTEL:
+ if ( core2_vpmu_init() )
+ vpmu_mode = XENPMU_MODE_OFF;
+ break;
+ default:
+ printk(XENLOG_WARNING "VPMU: Unknown CPU vendor: %d\n", vendor);
+ vpmu_mode = XENPMU_MODE_OFF;
+ break;
+ }
+
+ if ( vpmu_mode == XENPMU_MODE_OFF )
+ printk(XENLOG_WARNING "VPMU: Disabling due to initialization error\n");
+ else
+ printk(XENLOG_INFO "VPMU: version %s.%s\n",
+ __stringify(XENPMU_VER_MAJ), __stringify(XENPMU_VER_MIN));
+
+ return 0;
+}
+__initcall(vpmu_init);
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 1171b2a..cf32f82 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -62,7 +62,9 @@ struct arch_vpmu_ops {
void (*arch_vpmu_dump)(const struct vcpu *);
};
+int core2_vpmu_init(void);
int vmx_vpmu_initialise(struct vcpu *);
+int amd_vpmu_init(void);
int svm_vpmu_initialise(struct vcpu *);
/* VPMU states */
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall
2015-01-05 21:44 ` [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall Boris Ostrovsky
@ 2015-01-30 14:54 ` Jan Beulich
2015-02-03 16:02 ` Boris Ostrovsky
0 siblings, 1 reply; 31+ messages in thread
From: Jan Beulich @ 2015-01-30 14:54 UTC (permalink / raw)
To: Boris Ostrovsky
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
>>> On 05.01.15 at 22:44, <boris.ostrovsky@oracle.com> wrote:
> --- a/xen/arch/x86/hvm/vpmu.c
> +++ b/xen/arch/x86/hvm/vpmu.c
> @@ -497,3 +497,39 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
>
> return ret;
> }
> +
> +static int __init vpmu_init(void)
> +{
> + int vendor = current_cpu_data.x86_vendor;
> +
> + if ( vpmu_mode == XENPMU_MODE_OFF )
> + {
> + printk(XENLOG_INFO "VPMU: disabled\n");
> + return 0;
> + }
> +
> + switch ( vendor )
> + {
> + case X86_VENDOR_AMD:
> + if ( amd_vpmu_init() )
> + vpmu_mode = XENPMU_MODE_OFF;
> + break;
> + case X86_VENDOR_INTEL:
> + if ( core2_vpmu_init() )
> + vpmu_mode = XENPMU_MODE_OFF;
> + break;
> + default:
> + printk(XENLOG_WARNING "VPMU: Unknown CPU vendor: %d\n", vendor);
> + vpmu_mode = XENPMU_MODE_OFF;
> + break;
return 0;
(i.e. avoid printing another message below)
> + }
> +
> + if ( vpmu_mode == XENPMU_MODE_OFF )
> + printk(XENLOG_WARNING "VPMU: Disabling due to initialization error\n");
We repeatedly find that not printing at least a vague indication of
what went wrong makes problem analysis quite a bit more difficult.
It won't cost much to include the actual error code here.
> + else
> + printk(XENLOG_INFO "VPMU: version %s.%s\n",
> + __stringify(XENPMU_VER_MAJ), __stringify(XENPMU_VER_MIN));
%s and __stringify()? Either print the numbers with %d or %u, or
use __stringify() to avoid any argument besides the format string.
Jan
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall
2015-01-30 14:54 ` Jan Beulich
@ 2015-02-03 16:02 ` Boris Ostrovsky
2015-02-03 16:18 ` Jan Beulich
0 siblings, 1 reply; 31+ messages in thread
From: Boris Ostrovsky @ 2015-02-03 16:02 UTC (permalink / raw)
To: Jan Beulich
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
On 01/30/2015 09:54 AM, Jan Beulich wrote:
>>>> On 05.01.15 at 22:44, <boris.ostrovsky@oracle.com> wrote:
>> --- a/xen/arch/x86/hvm/vpmu.c
>> +++ b/xen/arch/x86/hvm/vpmu.c
>> @@ -497,3 +497,39 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
>>
>> return ret;
>> }
>> +
>> +static int __init vpmu_init(void)
>> +{
>> + int vendor = current_cpu_data.x86_vendor;
>> +
>> + if ( vpmu_mode == XENPMU_MODE_OFF )
>> + {
>> + printk(XENLOG_INFO "VPMU: disabled\n");
>> + return 0;
>> + }
>> +
>> + switch ( vendor )
>> + {
>> + case X86_VENDOR_AMD:
>> + if ( amd_vpmu_init() )
>> + vpmu_mode = XENPMU_MODE_OFF;
>> + break;
>> + case X86_VENDOR_INTEL:
>> + if ( core2_vpmu_init() )
>> + vpmu_mode = XENPMU_MODE_OFF;
>> + break;
>> + default:
>> + printk(XENLOG_WARNING "VPMU: Unknown CPU vendor: %d\n", vendor);
>> + vpmu_mode = XENPMU_MODE_OFF;
>> + break;
>
> return 0;
>
> (i.e. avoid printing another message below)
>
>> + }
>> +
>> + if ( vpmu_mode == XENPMU_MODE_OFF )
>> + printk(XENLOG_WARNING "VPMU: Disabling due to initialization error\n");
>
> We repeatedly find that not printing at least a vague indication of
> what went wrong makes problem analysis quite a bit more difficult.
> It won't cost much to include the actual error code here.
The actual error is printed by the architectural code (i.e.
amd_vpmu_init()/core2_vpmu_init()).
-boris
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall
2015-02-03 16:02 ` Boris Ostrovsky
@ 2015-02-03 16:18 ` Jan Beulich
0 siblings, 0 replies; 31+ messages in thread
From: Jan Beulich @ 2015-02-03 16:18 UTC (permalink / raw)
To: Boris Ostrovsky
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
>>> On 03.02.15 at 17:02, <boris.ostrovsky@oracle.com> wrote:
> On 01/30/2015 09:54 AM, Jan Beulich wrote:
>>>>> On 05.01.15 at 22:44, <boris.ostrovsky@oracle.com> wrote:
>>> +static int __init vpmu_init(void)
>>> +{
>>> + int vendor = current_cpu_data.x86_vendor;
>>> +
>>> + if ( vpmu_mode == XENPMU_MODE_OFF )
>>> + {
>>> + printk(XENLOG_INFO "VPMU: disabled\n");
>>> + return 0;
>>> + }
>>> +
>>> + switch ( vendor )
>>> + {
>>> + case X86_VENDOR_AMD:
>>> + if ( amd_vpmu_init() )
>>> + vpmu_mode = XENPMU_MODE_OFF;
>>> + break;
>>> + case X86_VENDOR_INTEL:
>>> + if ( core2_vpmu_init() )
>>> + vpmu_mode = XENPMU_MODE_OFF;
>>> + break;
>>> + default:
>>> + printk(XENLOG_WARNING "VPMU: Unknown CPU vendor: %d\n", vendor);
>>> + vpmu_mode = XENPMU_MODE_OFF;
>>> + break;
>>
>> return 0;
>>
>> (i.e. avoid printing another message below)
>>
>>> + }
>>> +
>>> + if ( vpmu_mode == XENPMU_MODE_OFF )
>>> + printk(XENLOG_WARNING "VPMU: Disabling due to initialization error\n");
>>
>> We repeatedly find that not printing at least a vague indication of
>> what went wrong makes problem analysis quite a bit more difficult.
>> It won't cost much to include the actual error code here.
>
>
> The actual error is printed by the architectural code (i.e.
> amd_vpmu_init()/core2_vpmu_init()).
Then don't print another message here.
Jan
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v17 15/23] x86/VPMU: Initialize PMU for PV(H) guests
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (13 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 14/23] x86/VPMU: Initialize VPMUs with __initcall Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 16/23] x86/VPMU: Save VPMU state for PV guests during context switch Boris Ostrovsky
` (8 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Code for initializing/tearing down PMU for PV guests
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
tools/flask/policy/policy/modules/xen/xen.te | 4 ++
xen/arch/x86/domain.c | 2 +
xen/arch/x86/hvm/hvm.c | 1 +
xen/arch/x86/hvm/svm/svm.c | 4 +-
xen/arch/x86/hvm/svm/vpmu.c | 44 ++++++++----
xen/arch/x86/hvm/vmx/vmx.c | 4 +-
xen/arch/x86/hvm/vmx/vpmu_core2.c | 79 +++++++++++++++------
xen/arch/x86/hvm/vpmu.c | 101 +++++++++++++++++++++++++--
xen/common/event_channel.c | 1 +
xen/include/asm-x86/hvm/vpmu.h | 2 +
xen/include/public/pmu.h | 2 +
xen/include/public/xen.h | 1 +
xen/include/xsm/dummy.h | 3 +
xen/xsm/flask/hooks.c | 4 ++
xen/xsm/flask/policy/access_vectors | 2 +
15 files changed, 211 insertions(+), 43 deletions(-)
diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te
index 870ff81..73bbe7b 100644
--- a/tools/flask/policy/policy/modules/xen/xen.te
+++ b/tools/flask/policy/policy/modules/xen/xen.te
@@ -120,6 +120,10 @@ domain_comms(dom0_t, dom0_t)
# Allow all domains to use (unprivileged parts of) the tmem hypercall
allow domain_type xen_t:xen tmem_op;
+# Allow all domains to use PMU (but not to change its settings --- that's what
+# pmu_ctrl is for)
+allow domain_type xen_t:xen2 pmu_use;
+
###############################################################################
#
# Domain creation
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index d00622d..a29db67 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -445,6 +445,8 @@ int vcpu_initialise(struct vcpu *v)
vmce_init_vcpu(v);
+ spin_lock_init(&v->arch.vpmu.vpmu_lock);
+
if ( has_hvm_container_domain(d) )
{
rc = hvm_vcpu_initialise(v);
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index bc414ff..737f3ea 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -4820,6 +4820,7 @@ static hvm_hypercall_t *const pvh_hypercall64_table[NR_hypercalls] = {
HYPERCALL(hvm_op),
HYPERCALL(sysctl),
HYPERCALL(domctl),
+ HYPERCALL(xenpmu_op),
[ __HYPERVISOR_arch_1 ] = (hvm_hypercall_t *)paging_domctl_continuation
};
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index a7655bd..59cca08 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1166,7 +1166,9 @@ static int svm_vcpu_initialise(struct vcpu *v)
return rc;
}
- vpmu_initialise(v);
+ /* PVH's VPMU is initialized via hypercall */
+ if ( is_hvm_vcpu(v) )
+ vpmu_initialise(v);
svm_guest_osvw_init(v);
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 03474a3..7eeefa2 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -379,17 +379,19 @@ static void amd_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- if ( has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
- amd_vpmu_unset_msr_bitmap(v);
+ if ( has_hvm_container_vcpu(v) )
+ {
+ if ( is_msr_bitmap_on(vpmu) )
+ amd_vpmu_unset_msr_bitmap(v);
- xfree(vpmu->context);
- vpmu_reset(vpmu, VPMU_CONTEXT_ALLOCATED);
+ if ( is_hvm_vcpu(v) )
+ xfree(vpmu->context);
- if ( vpmu_is_set(vpmu, VPMU_RUNNING) )
- {
- vpmu_reset(vpmu, VPMU_RUNNING);
release_pmu_ownship(PMU_OWNER_HVM);
}
+
+ vpmu->context = NULL;
+ vpmu_clear(vpmu);
}
/* VPMU part of the 'q' keyhandler */
@@ -456,15 +458,19 @@ int svm_vpmu_initialise(struct vcpu *v)
if ( !counters )
return -EINVAL;
- ctxt = xzalloc_bytes(sizeof(*ctxt) +
- 2 * sizeof(uint64_t) * num_counters);
- if ( !ctxt )
+ if ( is_hvm_vcpu(v) )
{
- printk(XENLOG_G_WARNING "Insufficient memory for PMU, "
- " PMU feature is unavailable on domain %d vcpu %d.\n",
- v->vcpu_id, v->domain->domain_id);
- return -ENOMEM;
+ ctxt = xzalloc_bytes(sizeof(*ctxt) +
+ 2 * sizeof(uint64_t) * num_counters);
+ if ( !ctxt )
+ {
+ printk(XENLOG_G_WARNING "%pv: Insufficient memory for PMU, "
+ " PMU feature is unavailable\n", v);
+ return -ENOMEM;
+ }
}
+ else
+ ctxt = &v->arch.vpmu.xenpmu_data->pmu.c.amd;
ctxt->counters = sizeof(*ctxt);
ctxt->ctrls = ctxt->counters + sizeof(uint64_t) * num_counters;
@@ -503,6 +509,16 @@ int __init amd_vpmu_init(void)
return -EINVAL;
}
+ if ( sizeof(struct xen_pmu_data) +
+ 2 * sizeof(uint64_t) * num_counters > PAGE_SIZE )
+ {
+ printk(XENLOG_WARNING
+ "VPMU: Register bank does not fit into VPMU shared page\n");
+ counters = ctrls = NULL;
+ num_counters = 0;
+ return -ENOSPC;
+ }
+
return 0;
}
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index f2554d6..2b6981e 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -116,7 +116,9 @@ static int vmx_vcpu_initialise(struct vcpu *v)
return rc;
}
- vpmu_initialise(v);
+ /* PVH's VPMU is initialized via hypercall */
+ if ( is_hvm_vcpu(v) )
+ vpmu_initialise(v);
vmx_install_vlapic_mapping(v);
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 6c78323..60f0f69 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -378,24 +378,34 @@ static int core2_vpmu_alloc_resource(struct vcpu *v)
struct xen_pmu_intel_ctxt *core2_vpmu_cxt = NULL;
uint64_t *p = NULL;
- if ( !acquire_pmu_ownership(PMU_OWNER_HVM) )
- return 0;
-
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
- if ( vmx_add_host_load_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
+ p = xzalloc(uint64_t);
+ if ( !p )
goto out_err;
- if ( vmx_add_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
- goto out_err;
- vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+ if ( has_hvm_container_vcpu(v) )
+ {
+ if ( is_hvm_vcpu(v) && !acquire_pmu_ownership(PMU_OWNER_HVM) )
+ goto out_err;
- core2_vpmu_cxt = xzalloc_bytes(sizeof(*core2_vpmu_cxt) +
- sizeof(uint64_t) * fixed_pmc_cnt +
- sizeof(struct xen_pmu_cntr_pair) *
- arch_pmc_cnt);
- p = xzalloc(uint64_t);
- if ( !core2_vpmu_cxt || !p )
- goto out_err;
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+ if ( vmx_add_host_load_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
+ goto out_err_hvm;
+ if ( vmx_add_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL) )
+ goto out_err_hvm;
+ vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
+ }
+
+ if ( is_hvm_vcpu(v) )
+ {
+ core2_vpmu_cxt = xzalloc_bytes(sizeof(*core2_vpmu_cxt) +
+ sizeof(uint64_t) * fixed_pmc_cnt +
+ sizeof(struct xen_pmu_cntr_pair) *
+ arch_pmc_cnt);
+ if ( !core2_vpmu_cxt )
+ goto out_err_hvm;
+ }
+ else
+ core2_vpmu_cxt = &v->arch.vpmu.xenpmu_data->pmu.c.intel;
core2_vpmu_cxt->fixed_counters = sizeof(*core2_vpmu_cxt);
core2_vpmu_cxt->arch_counters = core2_vpmu_cxt->fixed_counters +
@@ -408,10 +418,12 @@ static int core2_vpmu_alloc_resource(struct vcpu *v)
return 1;
-out_err:
- release_pmu_ownship(PMU_OWNER_HVM);
-
+ out_err_hvm:
xfree(core2_vpmu_cxt);
+ if ( is_hvm_vcpu(v) )
+ release_pmu_ownship(PMU_OWNER_HVM);
+
+ out_err:
xfree(p);
printk("Failed to allocate VPMU resources for domain %u vcpu %u\n",
@@ -728,12 +740,20 @@ static void core2_vpmu_destroy(struct vcpu *v)
{
struct vpmu_struct *vpmu = vcpu_vpmu(v);
- xfree(vpmu->context);
+ if ( has_hvm_container_vcpu(v) )
+ {
+ if ( cpu_has_vmx_msr_bitmap )
+ core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
+
+ if ( is_hvm_vcpu(v) )
+ xfree(vpmu->context);
+
+ release_pmu_ownship(PMU_OWNER_HVM);
+ }
+
xfree(vpmu->priv_context);
- if ( has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
- core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
- release_pmu_ownship(PMU_OWNER_HVM);
- vpmu_reset(vpmu, VPMU_CONTEXT_ALLOCATED);
+ vpmu->context = NULL;
+ vpmu_clear(vpmu);
}
struct arch_vpmu_ops core2_vpmu_ops = {
@@ -844,6 +864,10 @@ int vmx_vpmu_initialise(struct vcpu *v)
ds_warned = 1;
func_out:
+ /* PV domains can allocate resources immediately */
+ if ( is_pv_vcpu(v) && !core2_vpmu_alloc_resource(v) )
+ return -EIO;
+
vpmu->arch_vpmu_ops = &core2_vpmu_ops;
return 0;
@@ -906,5 +930,14 @@ int __init core2_vpmu_init(void)
check_pmc_quirk();
+ if ( sizeof(struct xen_pmu_data) + sizeof(uint64_t) * fixed_pmc_cnt +
+ sizeof(struct xen_pmu_cntr_pair) * arch_pmc_cnt > PAGE_SIZE )
+ {
+ printk(XENLOG_WARNING
+ "VPMU: Register bank does not fit into VPMU share page\n");
+ arch_pmc_cnt = fixed_pmc_cnt = 0;
+ return -ENOSPC;
+ }
+
return 0;
}
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index fbce557..3c6cbac 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -26,6 +26,7 @@
#include <asm/regs.h>
#include <asm/types.h>
#include <asm/msr.h>
+#include <asm/p2m.h>
#include <asm/hvm/support.h>
#include <asm/hvm/vmx/vmx.h>
#include <asm/hvm/vmx/vmcs.h>
@@ -244,9 +245,6 @@ void vpmu_initialise(struct vcpu *v)
uint8_t vendor = current_cpu_data.x86_vendor;
int ret;
- if ( is_pvh_vcpu(v) )
- return;
-
BUILD_BUG_ON(sizeof(struct xen_pmu_intel_ctxt) > XENPMU_CTXT_PAD_SZ);
BUILD_BUG_ON(sizeof(struct xen_pmu_amd_ctxt) > XENPMU_CTXT_PAD_SZ);
@@ -254,6 +252,7 @@ void vpmu_initialise(struct vcpu *v)
vpmu_destroy(v);
vpmu_clear(vpmu);
vpmu->context = NULL;
+ vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
switch ( vendor )
{
@@ -304,7 +303,89 @@ void vpmu_destroy(struct vcpu *v)
vpmu_clear_last, v, 1);
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_destroy )
+ {
+ /* Unload VPMU first. This will stop counters */
+ on_selected_cpus(cpumask_of(vcpu_vpmu(v)->last_pcpu),
+ vpmu_save_force, v, 1);
+
vpmu->arch_vpmu_ops->arch_vpmu_destroy(v);
+ }
+}
+
+static int pvpmu_init(struct domain *d, xen_pmu_params_t *params)
+{
+ struct vcpu *v;
+ struct vpmu_struct *vpmu;
+ struct page_info *page;
+ uint64_t gfn = params->val;
+
+ if ( vpmu_mode == XENPMU_MODE_OFF )
+ return -EINVAL;
+
+ if ( (params->vcpu >= d->max_vcpus) || (d->vcpu == NULL) ||
+ (d->vcpu[params->vcpu] == NULL) )
+ return -EINVAL;
+
+ page = get_page_from_gfn(d, gfn, NULL, P2M_ALLOC);
+ if ( !page )
+ return -EINVAL;
+
+ if ( !get_page_type(page, PGT_writable_page) )
+ {
+ put_page(page);
+ return -EINVAL;
+ }
+
+ v = d->vcpu[params->vcpu];
+ vpmu = vcpu_vpmu(v);
+ spin_lock(&vpmu->vpmu_lock);
+
+ v->arch.vpmu.xenpmu_data = __map_domain_page_global(page);
+ if ( !v->arch.vpmu.xenpmu_data )
+ {
+ put_page_and_type(page);
+ spin_unlock(&vpmu->vpmu_lock);
+ return -EINVAL;
+ }
+
+ vpmu_initialise(v);
+
+ spin_unlock(&vpmu->vpmu_lock);
+
+ return 0;
+}
+
+static void pvpmu_finish(struct domain *d, xen_pmu_params_t *params)
+{
+ struct vcpu *v;
+ struct vpmu_struct *vpmu;
+ uint64_t mfn;
+
+ if ( (params->vcpu >= d->max_vcpus) || (d->vcpu == NULL) ||
+ (d->vcpu[params->vcpu] == NULL) )
+ return;
+
+ v = d->vcpu[params->vcpu];
+ if ( v != current )
+ vcpu_pause(v);
+
+ vpmu = vcpu_vpmu(v);
+ spin_lock(&vpmu->vpmu_lock);
+
+ if ( v->arch.vpmu.xenpmu_data )
+ {
+ mfn = domain_page_map_to_mfn(v->arch.vpmu.xenpmu_data);
+ ASSERT(mfn != 0);
+ unmap_domain_page_global(v->arch.vpmu.xenpmu_data);
+ put_page_and_type(mfn_to_page(mfn));
+ v->arch.vpmu.xenpmu_data = NULL;
+ }
+ vpmu_destroy(v);
+
+ spin_unlock(&vpmu->vpmu_lock);
+
+ if ( v != current )
+ vcpu_unpause(v);
}
/* Dump some vpmu informations on console. Used in keyhandler dump_domains(). */
@@ -473,7 +554,7 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
if ( copy_to_guest(arg, &pmu_params, 1) )
return -EFAULT;
- break;
+ break;
case XENPMU_feature_set:
if ( copy_from_guest(&pmu_params, arg, 1) )
@@ -491,6 +572,18 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
return -EFAULT;
break;
+ case XENPMU_init:
+ if ( copy_from_guest(&pmu_params, arg, 1) )
+ return -EFAULT;
+ ret = pvpmu_init(current->domain, &pmu_params);
+ break;
+
+ case XENPMU_finish:
+ if ( copy_from_guest(&pmu_params, arg, 1) )
+ return -EFAULT;
+ pvpmu_finish(current->domain, &pmu_params);
+ break;
+
default:
ret = -EINVAL;
}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 7d6de54..a991b2d 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -108,6 +108,7 @@ static int virq_is_global(uint32_t virq)
case VIRQ_TIMER:
case VIRQ_DEBUG:
case VIRQ_XENOPROF:
+ case VIRQ_XENPMU:
rc = 0;
break;
case VIRQ_ARCH_0 ... VIRQ_ARCH_7:
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index cf32f82..42a09f9 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -44,6 +44,8 @@ struct vpmu_struct {
void *context; /* May be shared with PV guest */
void *priv_context; /* hypervisor-only */
struct arch_vpmu_ops *arch_vpmu_ops;
+ struct xen_pmu_data *xenpmu_data;
+ spinlock_t vpmu_lock;
};
/* Arch specific operations shared by all vpmus */
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index 66cc494..afb4ca1 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -25,6 +25,8 @@
#define XENPMU_mode_set 1
#define XENPMU_feature_get 2
#define XENPMU_feature_set 3
+#define XENPMU_init 4
+#define XENPMU_finish 5
/* ` } */
/* Parameters structure for HYPERVISOR_xenpmu_op call */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 0766790..e4d0b79 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -161,6 +161,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
#define VIRQ_MEM_EVENT 10 /* G. (DOM0) A memory event has occured */
#define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient */
#define VIRQ_ENOMEM 12 /* G. (DOM0) Low on heap memory */
+#define VIRQ_XENPMU 13 /* V. PMC interrupt */
/* Architecture-specific VIRQ definitions. */
#define VIRQ_ARCH_0 16
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index c637454..ae47135 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -665,6 +665,9 @@ static XSM_INLINE int xsm_pmu_op (XSM_DEFAULT_ARG struct domain *d, int op)
case XENPMU_feature_set:
case XENPMU_feature_get:
return xsm_default_action(XSM_PRIV, d, current->domain);
+ case XENPMU_init:
+ case XENPMU_finish:
+ return xsm_default_action(XSM_HOOK, d, current->domain);
default:
return -EPERM;
}
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index a24c480..e98715d 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -1517,6 +1517,10 @@ static int flask_pmu_op (struct domain *d, int op)
case XENPMU_feature_get:
return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_XEN2,
XEN2__PMU_CTRL, NULL);
+ case XENPMU_init:
+ case XENPMU_finish:
+ return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_XEN2,
+ XEN2__PMU_USE, NULL);
default:
return -EPERM;
}
diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors
index 4786a39..43908e8 100644
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -87,6 +87,8 @@ class xen2
get_symbol
# PMU control
pmu_ctrl
+# PMU use (domains, including unprivileged ones, will be using this operation)
+ pmu_use
}
# Classes domain and domain2 consist of operations that a domain performs on
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 16/23] x86/VPMU: Save VPMU state for PV guests during context switch
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (14 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 15/23] x86/VPMU: Initialize PMU for PV(H) guests Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 17/23] x86/VPMU: When handling MSR accesses, leave fault injection to callers Boris Ostrovsky
` (7 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Save VPMU state during context switch for both HVM and PV(H) guests.
A subsequent patch ("x86/VPMU: NMI-based VPMU support") will make it possible
for vpmu_switch_to() to call vmx_vmcs_try_enter()->vcpu_pause() which needs
is_running to be correctly set/cleared. To prepare for that, call context_saved()
before vpmu_switch_to() is executed. (Note that while this change could have
been dalayed until that later patch, the changes are harmless to existing code
and so we do it here)
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/domain.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index a29db67..7d5d46b 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1541,17 +1541,14 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
}
if ( prev != next )
- _update_runstate_area(prev);
-
- if ( is_hvm_vcpu(prev) )
{
- if (prev != next)
- vpmu_switch_from(vcpu_vpmu(prev), vcpu_vpmu(next));
-
- if ( !list_empty(&prev->arch.hvm_vcpu.tm_list) )
- pt_save_timer(prev);
+ _update_runstate_area(prev);
+ vpmu_switch_from(vcpu_vpmu(prev), vcpu_vpmu(next));
}
+ if ( is_hvm_vcpu(prev) && !list_empty(&prev->arch.hvm_vcpu.tm_list) )
+ pt_save_timer(prev);
+
local_irq_disable();
set_current(next);
@@ -1589,15 +1586,16 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
!is_hardware_domain(next->domain));
}
- if ( is_hvm_vcpu(next) && (prev != next) )
- /* Must be done with interrupts enabled */
- vpmu_switch_to(vcpu_vpmu(prev), vcpu_vpmu(next));
-
context_saved(prev);
if ( prev != next )
+ {
_update_runstate_area(next);
+ /* Must be done with interrupts enabled */
+ vpmu_switch_to(vcpu_vpmu(prev), vcpu_vpmu(next));
+ }
+
/* Ensure that the vcpu has an up-to-date time base. */
update_vcpu_system_time(next);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 17/23] x86/VPMU: When handling MSR accesses, leave fault injection to callers
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (15 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 16/23] x86/VPMU: Save VPMU state for PV guests during context switch Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 18/23] x86/VPMU: Add support for PMU register handling on PV guests Boris Ostrovsky
` (6 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
With this patch return value of 1 of vpmu_do_msr() will now indicate whether an
error was encountered during MSR processing (instead of stating that the access
was to a VPMU register).
As part of this patch we also check for validity of certain MSR accesses right
when we determine which register is being written, as opposed to postponing this
until later.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/svm/svm.c | 6 ++-
xen/arch/x86/hvm/svm/vpmu.c | 6 +--
xen/arch/x86/hvm/vmx/vmx.c | 24 +++++++++---
xen/arch/x86/hvm/vmx/vpmu_core2.c | 82 ++++++++++++++-------------------------
4 files changed, 55 insertions(+), 63 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 59cca08..a8cb9ae 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1709,7 +1709,8 @@ static int svm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
case MSR_AMD_FAM15H_EVNTSEL3:
case MSR_AMD_FAM15H_EVNTSEL4:
case MSR_AMD_FAM15H_EVNTSEL5:
- vpmu_do_rdmsr(msr, msr_content);
+ if ( vpmu_do_rdmsr(msr, msr_content) )
+ goto gpf;
break;
case MSR_AMD64_DR0_ADDRESS_MASK:
@@ -1860,7 +1861,8 @@ static int svm_msr_write_intercept(unsigned int msr, uint64_t msr_content)
case MSR_AMD_FAM15H_EVNTSEL3:
case MSR_AMD_FAM15H_EVNTSEL4:
case MSR_AMD_FAM15H_EVNTSEL5:
- vpmu_do_wrmsr(msr, msr_content, 0);
+ if ( vpmu_do_wrmsr(msr, msr_content, 0) )
+ goto gpf;
break;
case MSR_IA32_MCx_MISC(4): /* Threshold register */
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 7eeefa2..27c8a9c 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -324,7 +324,7 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
is_pmu_enabled(msr_content) && !vpmu_is_set(vpmu, VPMU_RUNNING) )
{
if ( !acquire_pmu_ownership(PMU_OWNER_HVM) )
- return 1;
+ return 0;
vpmu_set(vpmu, VPMU_RUNNING);
if ( has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) )
@@ -354,7 +354,7 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
/* Write to hw counters */
wrmsrl(msr, msr_content);
- return 1;
+ return 0;
}
static int amd_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
@@ -372,7 +372,7 @@ static int amd_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
rdmsrl(msr, *msr_content);
- return 1;
+ return 0;
}
static void amd_vpmu_destroy(struct vcpu *v)
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 2b6981e..012bca4 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -2112,12 +2112,17 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
*msr_content |= MSR_IA32_MISC_ENABLE_BTS_UNAVAIL |
MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
/* Perhaps vpmu will change some bits. */
+ /* FALLTHROUGH */
+ case MSR_P6_PERFCTR(0)...MSR_P6_PERFCTR(7):
+ case MSR_P6_EVNTSEL(0)...MSR_P6_EVNTSEL(3):
+ case MSR_CORE_PERF_FIXED_CTR0...MSR_CORE_PERF_FIXED_CTR2:
+ case MSR_CORE_PERF_FIXED_CTR_CTRL...MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ case MSR_IA32_PEBS_ENABLE:
+ case MSR_IA32_DS_AREA:
if ( vpmu_do_rdmsr(msr, msr_content) )
- goto done;
+ goto gp_fault;
break;
default:
- if ( vpmu_do_rdmsr(msr, msr_content) )
- break;
if ( passive_domain_do_rdmsr(msr, msr_content) )
goto done;
switch ( long_mode_do_msr_read(msr, msr_content) )
@@ -2293,7 +2298,7 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content)
if ( msr_content & ~supported )
{
/* Perhaps some other bits are supported in vpmu. */
- if ( !vpmu_do_wrmsr(msr, msr_content, supported) )
+ if ( vpmu_do_wrmsr(msr, msr_content, supported) )
break;
}
if ( msr_content & IA32_DEBUGCTLMSR_LBR )
@@ -2321,9 +2326,16 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content)
if ( !nvmx_msr_write_intercept(msr, msr_content) )
goto gp_fault;
break;
+ case MSR_P6_PERFCTR(0)...MSR_P6_PERFCTR(7):
+ case MSR_P6_EVNTSEL(0)...MSR_P6_EVNTSEL(7):
+ case MSR_CORE_PERF_FIXED_CTR0...MSR_CORE_PERF_FIXED_CTR2:
+ case MSR_CORE_PERF_FIXED_CTR_CTRL...MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ case MSR_IA32_PEBS_ENABLE:
+ case MSR_IA32_DS_AREA:
+ if ( vpmu_do_wrmsr(msr, msr_content, 0) )
+ goto gp_fault;
+ break;
default:
- if ( vpmu_do_wrmsr(msr, msr_content, 0) )
- return X86EMUL_OKAY;
if ( passive_domain_do_wrmsr(msr, msr_content) )
return X86EMUL_OKAY;
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 60f0f69..f5b9453 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -479,36 +479,41 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
IA32_DEBUGCTLMSR_BTS_OFF_USR;
if ( !(msr_content & ~supported) &&
vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) )
- return 1;
+ return 0;
if ( (msr_content & supported) &&
!vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) )
printk(XENLOG_G_WARNING
"%pv: Debug Store unsupported on this CPU\n",
current);
}
- return 0;
+ return 1;
}
ASSERT(!supported);
+ if ( type == MSR_TYPE_COUNTER &&
+ (msr_content &
+ ~((1ull << core2_get_bitwidth_fix_count()) - 1)) )
+ /* Writing unsupported bits to a fixed counter */
+ return 1;
+
core2_vpmu_cxt = vpmu->context;
enabled_cntrs = vpmu->priv_context;
switch ( msr )
{
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
core2_vpmu_cxt->global_status &= ~msr_content;
- return 1;
+ return 0;
case MSR_CORE_PERF_GLOBAL_STATUS:
gdprintk(XENLOG_INFO, "Can not write readonly MSR: "
"MSR_PERF_GLOBAL_STATUS(0x38E)!\n");
- hvm_inject_hw_exception(TRAP_gp_fault, 0);
return 1;
case MSR_IA32_PEBS_ENABLE:
if ( msr_content & 1 )
gdprintk(XENLOG_WARNING, "Guest is trying to enable PEBS, "
"which is not supported.\n");
core2_vpmu_cxt->pebs_enable = msr_content;
- return 1;
+ return 0;
case MSR_IA32_DS_AREA:
if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_DS) )
{
@@ -517,18 +522,21 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
gdprintk(XENLOG_WARNING,
"Illegal address for IA32_DS_AREA: %#" PRIx64 "x\n",
msr_content);
- hvm_inject_hw_exception(TRAP_gp_fault, 0);
return 1;
}
core2_vpmu_cxt->ds_area = msr_content;
break;
}
gdprintk(XENLOG_WARNING, "Guest setting of DTS is ignored.\n");
- return 1;
+ return 0;
case MSR_CORE_PERF_GLOBAL_CTRL:
global_ctrl = msr_content;
break;
case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ if ( msr_content &
+ ( ~((1ull << (fixed_pmc_cnt * FIXED_CTR_CTRL_BITS)) - 1)) )
+ return 1;
+
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
*enabled_cntrs &= ~(((1ULL << fixed_pmc_cnt) - 1) << 32);
if ( msr_content != 0 )
@@ -551,6 +559,9 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
+ if ( msr_content & (~((1ull << 32) - 1)) )
+ return 1;
+
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
if ( msr_content & (1ULL << 22) )
@@ -562,45 +573,17 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
}
}
+ if ( type != MSR_TYPE_GLOBAL )
+ wrmsrl(msr, msr_content);
+ else
+ vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+
if ( (global_ctrl & *enabled_cntrs) || (core2_vpmu_cxt->ds_area != 0) )
vpmu_set(vpmu, VPMU_RUNNING);
else
vpmu_reset(vpmu, VPMU_RUNNING);
- if ( type != MSR_TYPE_GLOBAL )
- {
- u64 mask;
- int inject_gp = 0;
- switch ( type )
- {
- case MSR_TYPE_ARCH_CTRL: /* MSR_P6_EVNTSEL[0,...] */
- mask = ~((1ull << 32) - 1);
- if (msr_content & mask)
- inject_gp = 1;
- break;
- case MSR_TYPE_CTRL: /* IA32_FIXED_CTR_CTRL */
- if ( msr == MSR_IA32_DS_AREA )
- break;
- /* 4 bits per counter, currently 3 fixed counters implemented. */
- mask = ~((1ull << (fixed_pmc_cnt * FIXED_CTR_CTRL_BITS)) - 1);
- if (msr_content & mask)
- inject_gp = 1;
- break;
- case MSR_TYPE_COUNTER: /* IA32_FIXED_CTR[0-2] */
- mask = ~((1ull << core2_get_bitwidth_fix_count()) - 1);
- if (msr_content & mask)
- inject_gp = 1;
- break;
- }
- if (inject_gp)
- hvm_inject_hw_exception(TRAP_gp_fault, 0);
- else
- wrmsrl(msr, msr_content);
- }
- else
- vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
-
- return 1;
+ return 0;
}
static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
@@ -628,19 +611,14 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
rdmsrl(msr, *msr_content);
}
}
- else
+ else if ( msr == MSR_IA32_MISC_ENABLE )
{
/* Extension for BTS */
- if ( msr == MSR_IA32_MISC_ENABLE )
- {
- if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) )
- *msr_content &= ~MSR_IA32_MISC_ENABLE_BTS_UNAVAIL;
- }
- else
- return 0;
+ if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) )
+ *msr_content &= ~MSR_IA32_MISC_ENABLE_BTS_UNAVAIL;
}
- return 1;
+ return 0;
}
static void core2_vpmu_do_cpuid(unsigned int input,
@@ -794,9 +772,9 @@ static int core2_no_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
{
int type = -1, index = -1;
if ( !is_core2_vpmu_msr(msr, &type, &index) )
- return 0;
+ return 1;
*msr_content = 0;
- return 1;
+ return 0;
}
/*
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 18/23] x86/VPMU: Add support for PMU register handling on PV guests
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (16 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 17/23] x86/VPMU: When handling MSR accesses, leave fault injection to callers Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 19/23] x86/VPMU: Handle PMU interrupts for " Boris Ostrovsky
` (5 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Intercept accesses to PMU MSRs and process them in VPMU module. If vpmu ops
for VCPU are not initialized (which is the case, for example, for PV guests that
are not "VPMU-enlightened") access to MSRs will return failure.
Dump VPMU state for all domains (HVM and PV) when requested.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/domain.c | 3 +--
xen/arch/x86/hvm/vmx/vpmu_core2.c | 53 +++++++++++++++++++++++++++++++--------
xen/arch/x86/hvm/vpmu.c | 3 +++
xen/arch/x86/traps.c | 50 +++++++++++++++++++++++++++++++++++-
4 files changed, 96 insertions(+), 13 deletions(-)
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 7d5d46b..db6e6ef 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -2081,8 +2081,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
{
paging_dump_vcpu_info(v);
- if ( is_hvm_vcpu(v) )
- vpmu_dump(v);
+ vpmu_dump(v);
}
void domain_cpuid(
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index f5b9453..8067d83 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -27,6 +27,7 @@
#include <asm/regs.h>
#include <asm/types.h>
#include <asm/apic.h>
+#include <asm/traps.h>
#include <asm/msr.h>
#include <asm/msr-index.h>
#include <asm/hvm/support.h>
@@ -299,19 +300,23 @@ static inline void __core2_vpmu_save(struct vpmu_struct *vpmu)
rdmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, fixed_counters[i]);
for ( i = 0; i < arch_pmc_cnt; i++ )
rdmsrl(MSR_IA32_PERFCTR0 + i, xen_pmu_cntr_pair[i].counter);
+
+ if ( !has_hvm_container_vcpu(vpmu_vcpu(vpmu)) )
+ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, core2_vpmu_cxt->global_status);
}
static int core2_vpmu_save(struct vpmu_struct *vpmu)
{
- struct vcpu *v;
+ struct vcpu *v = vpmu_vcpu(vpmu);
+
+ if ( !has_hvm_container_vcpu(v) )
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
if ( !vpmu_are_all_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED) )
return 0;
__core2_vpmu_save(vpmu);
- v = vpmu_vcpu(vpmu);
-
/* Unset PMU MSR bitmap to trap lazy load. */
if ( !vpmu_is_set(vpmu, VPMU_RUNNING) &&
has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap )
@@ -360,6 +365,13 @@ static inline void __core2_vpmu_load(struct vpmu_struct *vpmu)
wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, core2_vpmu_cxt->fixed_ctrl);
wrmsrl(MSR_IA32_DS_AREA, core2_vpmu_cxt->ds_area);
wrmsrl(MSR_IA32_PEBS_ENABLE, core2_vpmu_cxt->pebs_enable);
+
+ if ( !has_hvm_container_vcpu(vpmu_vcpu(vpmu)) )
+ {
+ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, core2_vpmu_cxt->global_ovf_ctrl);
+ core2_vpmu_cxt->global_ovf_ctrl = 0;
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, core2_vpmu_cxt->global_ctrl);
+ }
}
static void core2_vpmu_load(struct vpmu_struct *vpmu)
@@ -458,7 +470,6 @@ static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
uint64_t supported)
{
- u64 global_ctrl;
int i, tmp;
int type = -1, index = -1;
struct vcpu *v = current;
@@ -502,7 +513,12 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
switch ( msr )
{
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ if ( msr_content & ~(0xC000000000000000 |
+ (((1ULL << fixed_pmc_cnt) - 1) << 32) |
+ ((1ULL << arch_pmc_cnt) - 1)) )
+ return 1;
core2_vpmu_cxt->global_status &= ~msr_content;
+ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, msr_content);
return 0;
case MSR_CORE_PERF_GLOBAL_STATUS:
gdprintk(XENLOG_INFO, "Can not write readonly MSR: "
@@ -530,14 +546,18 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
gdprintk(XENLOG_WARNING, "Guest setting of DTS is ignored.\n");
return 0;
case MSR_CORE_PERF_GLOBAL_CTRL:
- global_ctrl = msr_content;
+ core2_vpmu_cxt->global_ctrl = msr_content;
break;
case MSR_CORE_PERF_FIXED_CTR_CTRL:
if ( msr_content &
( ~((1ull << (fixed_pmc_cnt * FIXED_CTR_CTRL_BITS)) - 1)) )
return 1;
- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
+ if ( has_hvm_container_vcpu(v) )
+ vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL,
+ &core2_vpmu_cxt->global_ctrl);
+ else
+ rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, core2_vpmu_cxt->global_ctrl);
*enabled_cntrs &= ~(((1ULL << fixed_pmc_cnt) - 1) << 32);
if ( msr_content != 0 )
{
@@ -562,7 +582,11 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( msr_content & (~((1ull << 32) - 1)) )
return 1;
- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
+ if ( has_hvm_container_vcpu(v) )
+ vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL,
+ &core2_vpmu_cxt->global_ctrl);
+ else
+ rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, core2_vpmu_cxt->global_ctrl);
if ( msr_content & (1ULL << 22) )
*enabled_cntrs |= 1ULL << tmp;
@@ -576,9 +600,15 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
if ( type != MSR_TYPE_GLOBAL )
wrmsrl(msr, msr_content);
else
- vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+ {
+ if ( has_hvm_container_vcpu(v) )
+ vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+ else
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+ }
- if ( (global_ctrl & *enabled_cntrs) || (core2_vpmu_cxt->ds_area != 0) )
+ if ( (core2_vpmu_cxt->global_ctrl & *enabled_cntrs) ||
+ (core2_vpmu_cxt->ds_area != 0) )
vpmu_set(vpmu, VPMU_RUNNING);
else
vpmu_reset(vpmu, VPMU_RUNNING);
@@ -605,7 +635,10 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
*msr_content = core2_vpmu_cxt->global_status;
break;
case MSR_CORE_PERF_GLOBAL_CTRL:
- vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+ if ( has_hvm_container_vcpu(v) )
+ vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+ else
+ rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, *msr_content);
break;
default:
rdmsrl(msr, *msr_content);
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 3c6cbac..800d98c 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -110,6 +110,9 @@ int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_rdmsr )
return vpmu->arch_vpmu_ops->do_rdmsr(msr, msr_content);
+ else
+ *msr_content = 0;
+
return 0;
}
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 10fc2ca..70477b2 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -72,6 +72,7 @@
#include <asm/apic.h>
#include <asm/mc146818rtc.h>
#include <asm/hpet.h>
+#include <asm/hvm/vpmu.h>
#include <public/arch-x86/cpuid.h>
#include <xsm/xsm.h>
@@ -896,8 +897,10 @@ void pv_cpuid(struct cpu_user_regs *regs)
__clear_bit(X86_FEATURE_TOPOEXT % 32, &c);
break;
+ case 0x0000000a: /* Architectural Performance Monitor Features (Intel) */
+ break;
+
case 0x00000005: /* MONITOR/MWAIT */
- case 0x0000000a: /* Architectural Performance Monitor Features */
case 0x0000000b: /* Extended Topology Enumeration */
case 0x8000000a: /* SVM revision and features */
case 0x8000001b: /* Instruction Based Sampling */
@@ -913,6 +916,9 @@ void pv_cpuid(struct cpu_user_regs *regs)
}
out:
+ /* VPMU may decide to modify some of the leaves */
+ vpmu_do_cpuid(regs->eax, &a, &b, &c, &d);
+
regs->eax = a;
regs->ebx = b;
regs->ecx = c;
@@ -1935,6 +1941,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
char io_emul_stub[32];
void (*io_emul)(struct cpu_user_regs *) __attribute__((__regparm__(1)));
uint64_t val, msr_content;
+ bool_t vpmu_msr;
if ( !read_descriptor(regs->cs, v, regs,
&code_base, &code_limit, &ar,
@@ -2425,6 +2432,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
uint32_t eax = regs->eax;
uint32_t edx = regs->edx;
msr_content = ((uint64_t)edx << 32) | eax;
+ vpmu_msr = 0;
switch ( (u32)regs->ecx )
{
case MSR_FS_BASE:
@@ -2561,6 +2569,22 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
if ( v->arch.debugreg[7] & DR7_ACTIVE_MASK )
wrmsrl(regs->_ecx, msr_content);
break;
+ case MSR_P6_PERFCTR(0)...MSR_P6_PERFCTR(7):
+ case MSR_P6_EVNTSEL(0)...MSR_P6_EVNTSEL(3):
+ case MSR_CORE_PERF_FIXED_CTR0...MSR_CORE_PERF_FIXED_CTR2:
+ case MSR_CORE_PERF_FIXED_CTR_CTRL...MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
+ {
+ vpmu_msr = 1;
+ case MSR_AMD_FAM15H_EVNTSEL0...MSR_AMD_FAM15H_PERFCTR5:
+ if ( vpmu_msr || (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) )
+ {
+ if ( vpmu_do_wrmsr(regs->ecx, msr_content, 0) )
+ goto fail;
+ }
+ break;
+ }
+ /*FALLTHROUGH*/
default:
if ( wrmsr_hypervisor_regs(regs->ecx, msr_content) == 1 )
@@ -2593,6 +2617,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
break;
case 0x32: /* RDMSR */
+ vpmu_msr = 0;
switch ( (u32)regs->ecx )
{
case MSR_FS_BASE:
@@ -2663,6 +2688,29 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
[regs->_ecx - MSR_AMD64_DR1_ADDRESS_MASK + 1];
regs->edx = 0;
break;
+ case MSR_IA32_PERF_CAPABILITIES:
+ /* No extra capabilities are supported */
+ regs->eax = regs->edx = 0;
+ break;
+ case MSR_P6_PERFCTR(0)...MSR_P6_PERFCTR(7):
+ case MSR_P6_EVNTSEL(0)...MSR_P6_EVNTSEL(3):
+ case MSR_CORE_PERF_FIXED_CTR0...MSR_CORE_PERF_FIXED_CTR2:
+ case MSR_CORE_PERF_FIXED_CTR_CTRL...MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
+ {
+ vpmu_msr = 1;
+ case MSR_AMD_FAM15H_EVNTSEL0...MSR_AMD_FAM15H_PERFCTR5:
+ if ( vpmu_msr || (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) )
+ {
+ if ( vpmu_do_rdmsr(regs->ecx, &msr_content) )
+ goto fail;
+
+ regs->eax = (uint32_t)msr_content;
+ regs->edx = (uint32_t)(msr_content >> 32);
+ }
+ break;
+ }
+ /*FALLTHROUGH*/
default:
if ( rdmsr_hypervisor_regs(regs->ecx, &val) )
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 19/23] x86/VPMU: Handle PMU interrupts for PV guests
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (17 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 18/23] x86/VPMU: Add support for PMU register handling on PV guests Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 20/23] x86/VPMU: Merge vpmu_rdmsr and vpmu_wrmsr Boris Ostrovsky
` (4 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Add support for handling PMU interrupts for PV guests.
VPMU for the interrupted VCPU is unloaded until the guest issues XENPMU_flush
hypercall. This allows the guest to access PMU MSR values that are stored in
VPMU context which is shared between hypervisor and domain, thus avoiding
traps to hypervisor.
Since the interrupt handler may now force VPMU context save (i.e. set
VPMU_CONTEXT_SAVE flag) we need to make changes to amd_vpmu_save() which
until now expected this flag to be set only when the counters were stopped.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/svm/vpmu.c | 11 +-
xen/arch/x86/hvm/vpmu.c | 208 ++++++++++++++++++++++++++++++++++++--
xen/include/public/arch-x86/pmu.h | 6 ++
xen/include/public/pmu.h | 2 +
xen/include/xsm/dummy.h | 4 +-
xen/xsm/flask/hooks.c | 2 +
6 files changed, 213 insertions(+), 20 deletions(-)
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 27c8a9c..68113c7 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -225,17 +225,12 @@ static int amd_vpmu_save(struct vpmu_struct *vpmu)
struct vcpu *v;
unsigned int i;
- /*
- * Stop the counters. If we came here via vpmu_save_force (i.e.
- * when VPMU_CONTEXT_SAVE is set) counters are already stopped.
- */
+ for ( i = 0; i < num_counters; i++ )
+ wrmsrl(ctrls[i], 0);
+
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_SAVE) )
{
vpmu_set(vpmu, VPMU_FROZEN);
-
- for ( i = 0; i < num_counters; i++ )
- wrmsrl(ctrls[i], 0);
-
return 0;
}
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 800d98c..c57b250 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -80,27 +80,52 @@ static void __init parse_vpmu_param(char *s)
void vpmu_lvtpc_update(uint32_t val)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(current);
+ struct vcpu *curr = current;
+ struct vpmu_struct *vpmu = vcpu_vpmu(curr);
vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | (val & APIC_LVT_MASKED);
- apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
+
+ /* Postpone APIC updates for PV(H) guests if PMU interrupt is pending */
+ if ( is_hvm_vcpu(curr) || !vpmu->xenpmu_data ||
+ !(vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED) )
+ apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
}
int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(current);
+ struct vcpu *curr = current;
+ struct vpmu_struct *vpmu;
if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
return 0;
+ vpmu = vcpu_vpmu(curr);
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_wrmsr )
- return vpmu->arch_vpmu_ops->do_wrmsr(msr, msr_content, supported);
+ {
+ int ret = vpmu->arch_vpmu_ops->do_wrmsr(msr, msr_content, supported);
+
+ /*
+ * We may have received a PMU interrupt during WRMSR handling
+ * and since do_wrmsr may load VPMU context we should save
+ * (and unload) it again.
+ */
+ if ( !is_hvm_vcpu(curr) && vpmu->xenpmu_data &&
+ (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED) )
+ {
+ vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
+ vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu);
+ vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
+ }
+ return ret;
+ }
+
return 0;
}
int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
{
- struct vpmu_struct *vpmu = vcpu_vpmu(current);
+ struct vcpu *curr = current;
+ struct vpmu_struct *vpmu;
if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
{
@@ -108,24 +133,161 @@ int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
return 0;
}
+ vpmu = vcpu_vpmu(curr);
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_rdmsr )
- return vpmu->arch_vpmu_ops->do_rdmsr(msr, msr_content);
+ {
+ int ret = vpmu->arch_vpmu_ops->do_rdmsr(msr, msr_content);
+
+ if ( !is_hvm_vcpu(curr) && vpmu->xenpmu_data &&
+ (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED) )
+ {
+ vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
+ vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu);
+ vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
+ }
+ return ret;
+ }
else
*msr_content = 0;
return 0;
}
+static struct vcpu *choose_hwdom_vcpu(void)
+{
+ unsigned idx = smp_processor_id() % hardware_domain->max_vcpus;
+
+ if ( hardware_domain->vcpu == NULL )
+ return NULL;
+
+ return hardware_domain->vcpu[idx];
+}
+
void vpmu_do_interrupt(struct cpu_user_regs *regs)
{
- struct vcpu *v = current;
- struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct vcpu *sampled = current, *sampling;
+ struct vpmu_struct *vpmu;
+
+ /* dom0 will handle interrupt for special domains (e.g. idle domain) */
+ if ( sampled->domain->domain_id >= DOMID_FIRST_RESERVED )
+ {
+ sampling = choose_hwdom_vcpu();
+ if ( !sampling )
+ return;
+ }
+ else
+ sampling = sampled;
+
+ vpmu = vcpu_vpmu(sampling);
+ if ( !is_hvm_vcpu(sampling) )
+ {
+ /* PV(H) guest */
+ const struct cpu_user_regs *cur_regs;
+ uint64_t *flags = &vpmu->xenpmu_data->pmu.pmu_flags;
+ uint32_t domid = DOMID_SELF;
+
+ if ( !vpmu->xenpmu_data )
+ return;
+
+ if ( *flags & PMU_CACHED )
+ return;
+
+ if ( is_pvh_vcpu(sampling) &&
+ !vpmu->arch_vpmu_ops->do_interrupt(regs) )
+ return;
+
+ /* PV guest will be reading PMU MSRs from xenpmu_data */
+ vpmu_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
+ vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu);
+ vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
+
+ if ( has_hvm_container_vcpu(sampled) )
+ *flags = 0;
+ else
+ *flags = PMU_SAMPLE_PV;
+
+ /* Store appropriate registers in xenpmu_data */
+ /* FIXME: 32-bit PVH should go here as well */
+ if ( is_pv_32bit_vcpu(sampling) )
+ {
+ /*
+ * 32-bit dom0 cannot process Xen's addresses (which are 64 bit)
+ * and therefore we treat it the same way as a non-privileged
+ * PV 32-bit domain.
+ */
+ struct compat_pmu_regs *cmp;
+
+ cur_regs = guest_cpu_user_regs();
+
+ cmp = (void *)&vpmu->xenpmu_data->pmu.r.regs;
+ cmp->ip = cur_regs->rip;
+ cmp->sp = cur_regs->rsp;
+ cmp->flags = cur_regs->eflags;
+ cmp->ss = cur_regs->ss;
+ cmp->cs = cur_regs->cs;
+ if ( (cmp->cs & 3) > 1 )
+ *flags |= PMU_SAMPLE_USER;
+ }
+ else
+ {
+ struct xen_pmu_regs *r = &vpmu->xenpmu_data->pmu.r.regs;
+
+ if ( (vpmu_mode & XENPMU_MODE_SELF) )
+ cur_regs = guest_cpu_user_regs();
+ else if ( !guest_mode(regs) && is_hardware_domain(sampling->domain) )
+ {
+ cur_regs = regs;
+ domid = DOMID_XEN;
+ }
+ else
+ cur_regs = guest_cpu_user_regs();
+
+ r->ip = cur_regs->rip;
+ r->sp = cur_regs->rsp;
+ r->flags = cur_regs->eflags;
+
+ if ( !has_hvm_container_vcpu(sampled) )
+ {
+ r->ss = cur_regs->ss;
+ r->cs = cur_regs->cs;
+ if ( !(sampled->arch.flags & TF_kernel_mode) )
+ *flags |= PMU_SAMPLE_USER;
+ }
+ else
+ {
+ struct segment_register seg;
+
+ hvm_get_segment_register(sampled, x86_seg_cs, &seg);
+ r->cs = seg.sel;
+ hvm_get_segment_register(sampled, x86_seg_ss, &seg);
+ r->ss = seg.sel;
+ r->cpl = seg.attr.fields.dpl;
+ if ( !(sampled->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) )
+ *flags |= PMU_SAMPLE_REAL;
+ }
+ }
+
+ vpmu->xenpmu_data->domain_id = domid;
+ vpmu->xenpmu_data->vcpu_id = sampled->vcpu_id;
+ vpmu->xenpmu_data->pcpu_id = smp_processor_id();
+
+ *flags |= PMU_CACHED;
+ vpmu->hw_lapic_lvtpc |= APIC_LVT_MASKED;
+ apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
+
+ send_guest_vcpu_virq(sampling, VIRQ_XENPMU);
+
+ return;
+ }
if ( vpmu->arch_vpmu_ops )
{
- struct vlapic *vlapic = vcpu_vlapic(v);
+ struct vlapic *vlapic = vcpu_vlapic(sampling);
u32 vlapic_lvtpc;
+ /* We don't support (yet) HVM dom0 */
+ ASSERT(sampling == sampled);
+
if ( !vpmu->arch_vpmu_ops->do_interrupt(regs) ||
!is_vlapic_lvtpc_enabled(vlapic) )
return;
@@ -138,7 +300,7 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
vlapic_set_irq(vlapic, vlapic_lvtpc & APIC_VECTOR_MASK, 0);
break;
case APIC_MODE_NMI:
- v->nmi_pending = 1;
+ sampling->nmi_pending = 1;
break;
}
}
@@ -231,7 +393,9 @@ void vpmu_load(struct vpmu_struct *vpmu)
local_irq_enable();
/* Only when PMU is counting, we load PMU context immediately. */
- if ( !vpmu_is_set(vpmu, VPMU_RUNNING) )
+ if ( !vpmu_is_set(vpmu, VPMU_RUNNING) ||
+ (!is_hvm_vcpu(vpmu_vcpu(vpmu)) &&
+ (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED)) )
return;
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_load )
@@ -250,6 +414,8 @@ void vpmu_initialise(struct vcpu *v)
BUILD_BUG_ON(sizeof(struct xen_pmu_intel_ctxt) > XENPMU_CTXT_PAD_SZ);
BUILD_BUG_ON(sizeof(struct xen_pmu_amd_ctxt) > XENPMU_CTXT_PAD_SZ);
+ BUILD_BUG_ON(sizeof(struct xen_pmu_regs) > XENPMU_REGS_PAD_SZ);
+ BUILD_BUG_ON(sizeof(struct compat_pmu_regs) > XENPMU_REGS_PAD_SZ);
if ( vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
vpmu_destroy(v);
@@ -496,7 +662,9 @@ static int vpmu_unload_all(unsigned long old_mode)
long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
{
int ret;
+ struct vcpu *curr;
struct xen_pmu_params pmu_params;
+ struct xen_pmu_data *xenpmu_data;
ret = xsm_pmu_op(XSM_OTHER, current->domain, op);
if ( ret )
@@ -587,6 +755,24 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
pvpmu_finish(current->domain, &pmu_params);
break;
+ case XENPMU_lvtpc_set:
+ curr = current;
+ xenpmu_data = curr->arch.vpmu.xenpmu_data;
+ if ( xenpmu_data == NULL )
+ return -EINVAL;
+ vpmu_lvtpc_update(xenpmu_data->pmu.l.lapic_lvtpc);
+ break;
+
+ case XENPMU_flush:
+ curr = current;
+ xenpmu_data = curr->arch.vpmu.xenpmu_data;
+ if ( xenpmu_data == NULL )
+ return -EINVAL;
+ xenpmu_data->pmu.pmu_flags &= ~PMU_CACHED;
+ vpmu_lvtpc_update(xenpmu_data->pmu.l.lapic_lvtpc);
+ vpmu_load(vcpu_vpmu(curr));
+ break;
+
default:
ret = -EINVAL;
}
diff --git a/xen/include/public/arch-x86/pmu.h b/xen/include/public/arch-x86/pmu.h
index 8bbe341..74a91ac 100644
--- a/xen/include/public/arch-x86/pmu.h
+++ b/xen/include/public/arch-x86/pmu.h
@@ -51,6 +51,12 @@ struct xen_pmu_regs {
typedef struct xen_pmu_regs xen_pmu_regs_t;
DEFINE_XEN_GUEST_HANDLE(xen_pmu_regs_t);
+/* PMU flags */
+#define PMU_CACHED (1<<0) /* PMU MSRs are cached in the context */
+#define PMU_SAMPLE_USER (1<<1) /* Sample is from user or kernel mode */
+#define PMU_SAMPLE_REAL (1<<2) /* Sample is from realmode */
+#define PMU_SAMPLE_PV (1<<3) /* Sample from a PV guest */
+
struct xen_pmu_arch {
union {
struct xen_pmu_regs regs;
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index afb4ca1..db5321a 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -27,6 +27,8 @@
#define XENPMU_feature_set 3
#define XENPMU_init 4
#define XENPMU_finish 5
+#define XENPMU_lvtpc_set 6
+#define XENPMU_flush 7 /* Write cached MSR values to HW */
/* ` } */
/* Parameters structure for HYPERVISOR_xenpmu_op call */
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index ae47135..1ad4ecc 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -666,7 +666,9 @@ static XSM_INLINE int xsm_pmu_op (XSM_DEFAULT_ARG struct domain *d, int op)
case XENPMU_feature_get:
return xsm_default_action(XSM_PRIV, d, current->domain);
case XENPMU_init:
- case XENPMU_finish:
+ case XENPMU_finish:
+ case XENPMU_lvtpc_set:
+ case XENPMU_flush:
return xsm_default_action(XSM_HOOK, d, current->domain);
default:
return -EPERM;
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index e98715d..ced1468 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -1519,6 +1519,8 @@ static int flask_pmu_op (struct domain *d, int op)
XEN2__PMU_CTRL, NULL);
case XENPMU_init:
case XENPMU_finish:
+ case XENPMU_lvtpc_set:
+ case XENPMU_flush:
return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_XEN2,
XEN2__PMU_USE, NULL);
default:
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 20/23] x86/VPMU: Merge vpmu_rdmsr and vpmu_wrmsr
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (18 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 19/23] x86/VPMU: Handle PMU interrupts for " Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 21/23] x86/VPMU: Add privileged PMU mode Boris Ostrovsky
` (3 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
The two routines share most of their logic.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
xen/arch/x86/hvm/vpmu.c | 77 ++++++++++++++++--------------------------
xen/include/asm-x86/hvm/vpmu.h | 14 ++++++--
2 files changed, 42 insertions(+), 49 deletions(-)
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index c57b250..79391b6 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -91,65 +91,48 @@ void vpmu_lvtpc_update(uint32_t val)
apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
}
-int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported)
+int vpmu_do_msr(unsigned int msr, uint64_t *msr_content,
+ uint64_t supported, bool_t is_write)
{
- struct vcpu *curr = current;
+ struct vcpu *curr;
struct vpmu_struct *vpmu;
+ struct arch_vpmu_ops *ops;
+ int ret = 0;
if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
- return 0;
+ goto nop;
+ curr = current;
vpmu = vcpu_vpmu(curr);
- if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_wrmsr )
- {
- int ret = vpmu->arch_vpmu_ops->do_wrmsr(msr, msr_content, supported);
-
- /*
- * We may have received a PMU interrupt during WRMSR handling
- * and since do_wrmsr may load VPMU context we should save
- * (and unload) it again.
- */
- if ( !is_hvm_vcpu(curr) && vpmu->xenpmu_data &&
- (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED) )
- {
- vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
- vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu);
- vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
- }
- return ret;
- }
-
- return 0;
-}
-
-int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
-{
- struct vcpu *curr = current;
- struct vpmu_struct *vpmu;
+ ops = vpmu->arch_vpmu_ops;
+ if ( !ops )
+ goto nop;
+
+ if ( is_write && ops->do_wrmsr )
+ ret = ops->do_wrmsr(msr, *msr_content, supported);
+ else if ( !is_write && ops->do_rdmsr )
+ ret = ops->do_rdmsr(msr, msr_content);
+ else
+ goto nop;
- if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
+ /*
+ * We may have received a PMU interrupt while handling MSR access
+ * and since do_wr/rdmsr may load VPMU context we should save
+ * (and unload) it again.
+ */
+ if ( !is_hvm_vcpu(curr) &&
+ vpmu->xenpmu_data && (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED) )
{
- *msr_content = 0;
- return 0;
+ vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
+ ops->arch_vpmu_save(vpmu);
+ vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
}
- vpmu = vcpu_vpmu(curr);
- if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->do_rdmsr )
- {
- int ret = vpmu->arch_vpmu_ops->do_rdmsr(msr, msr_content);
+ return ret;
- if ( !is_hvm_vcpu(curr) && vpmu->xenpmu_data &&
- (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED) )
- {
- vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
- vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu);
- vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
- }
- return ret;
- }
- else
+ nop:
+ if ( !is_write )
*msr_content = 0;
-
return 0;
}
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 42a09f9..2c888cc 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -100,8 +100,8 @@ static inline bool_t vpmu_are_all_set(const struct vpmu_struct *vpmu,
}
void vpmu_lvtpc_update(uint32_t val);
-int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content, uint64_t supported);
-int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content);
+int vpmu_do_msr(unsigned int msr, uint64_t *msr_content,
+ uint64_t supported, bool_t is_write);
void vpmu_do_interrupt(struct cpu_user_regs *regs);
void vpmu_do_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
@@ -112,6 +112,16 @@ void vpmu_load(struct vpmu_struct *vpmu);
void vpmu_unload(struct vpmu_struct *vpmu);
void vpmu_dump(struct vcpu *v);
+static inline int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content,
+ uint64_t supported)
+{
+ return vpmu_do_msr(msr, &msr_content, supported, 1);
+}
+static inline int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
+{
+ return vpmu_do_msr(msr, msr_content, 0, 0);
+}
+
extern int acquire_pmu_ownership(int pmu_ownership);
extern void release_pmu_ownership(int pmu_ownership);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 21/23] x86/VPMU: Add privileged PMU mode
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (19 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 20/23] x86/VPMU: Merge vpmu_rdmsr and vpmu_wrmsr Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 22/23] x86/VPMU: NMI-based VPMU support Boris Ostrovsky
` (2 subsequent siblings)
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Add support for privileged PMU mode (XENPMU_MODE_ALL) which allows privileged
domain (dom0) profile both itself (and the hypervisor) and the guests. While
this mode is on profiling in guests is disabled.
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/hvm/vpmu.c | 40 ++++++++++++++++++++++++++++++----------
xen/arch/x86/traps.c | 12 ++++++++++++
xen/include/public/pmu.h | 3 +++
3 files changed, 45 insertions(+), 10 deletions(-)
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index 79391b6..ebab0f5 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -99,7 +99,9 @@ int vpmu_do_msr(unsigned int msr, uint64_t *msr_content,
struct arch_vpmu_ops *ops;
int ret = 0;
- if ( !(vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV)) )
+ if ( (vpmu_mode == XENPMU_MODE_OFF) ||
+ ((vpmu_mode & XENPMU_MODE_ALL) &&
+ !is_hardware_domain(current->domain)) )
goto nop;
curr = current;
@@ -151,8 +153,12 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
struct vcpu *sampled = current, *sampling;
struct vpmu_struct *vpmu;
- /* dom0 will handle interrupt for special domains (e.g. idle domain) */
- if ( sampled->domain->domain_id >= DOMID_FIRST_RESERVED )
+ /*
+ * dom0 will handle interrupt for special domains (e.g. idle domain) or,
+ * in XENPMU_MODE_ALL, for everyone.
+ */
+ if ( (vpmu_mode & XENPMU_MODE_ALL) ||
+ (sampled->domain->domain_id >= DOMID_FIRST_RESERVED) )
{
sampling = choose_hwdom_vcpu();
if ( !sampling )
@@ -162,12 +168,12 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
sampling = sampled;
vpmu = vcpu_vpmu(sampling);
- if ( !is_hvm_vcpu(sampling) )
+ if ( !is_hvm_vcpu(sampling) || (vpmu_mode & XENPMU_MODE_ALL) )
{
/* PV(H) guest */
const struct cpu_user_regs *cur_regs;
uint64_t *flags = &vpmu->xenpmu_data->pmu.pmu_flags;
- uint32_t domid = DOMID_SELF;
+ uint32_t domid;
if ( !vpmu->xenpmu_data )
return;
@@ -176,6 +182,7 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
return;
if ( is_pvh_vcpu(sampling) &&
+ !(vpmu_mode & XENPMU_MODE_ALL) &&
!vpmu->arch_vpmu_ops->do_interrupt(regs) )
return;
@@ -189,6 +196,11 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
else
*flags = PMU_SAMPLE_PV;
+ if ( sampled == sampling )
+ domid = DOMID_SELF;
+ else
+ domid = sampled->domain->domain_id;
+
/* Store appropriate registers in xenpmu_data */
/* FIXME: 32-bit PVH should go here as well */
if ( is_pv_32bit_vcpu(sampling) )
@@ -217,7 +229,8 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
if ( (vpmu_mode & XENPMU_MODE_SELF) )
cur_regs = guest_cpu_user_regs();
- else if ( !guest_mode(regs) && is_hardware_domain(sampling->domain) )
+ else if ( !guest_mode(regs) &&
+ is_hardware_domain(sampling->domain) )
{
cur_regs = regs;
domid = DOMID_XEN;
@@ -471,7 +484,8 @@ static int pvpmu_init(struct domain *d, xen_pmu_params_t *params)
struct page_info *page;
uint64_t gfn = params->val;
- if ( vpmu_mode == XENPMU_MODE_OFF )
+ if ( (vpmu_mode == XENPMU_MODE_OFF) ||
+ ((vpmu_mode & XENPMU_MODE_ALL) && !is_hardware_domain(d)) )
return -EINVAL;
if ( (params->vcpu >= d->max_vcpus) || (d->vcpu == NULL) ||
@@ -551,6 +565,10 @@ void vpmu_dump(struct vcpu *v)
void vpmu_unload(struct vpmu_struct *vpmu)
{
+ if ( (vpmu_mode & XENPMU_MODE_ALL) &&
+ is_hardware_domain(vpmu_vcpu(vpmu)->domain) )
+ return;
+
if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED | VPMU_RUNNING) )
return;
@@ -663,11 +681,13 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
if ( copy_from_guest(&pmu_params, arg, 1) )
return -EFAULT;
- if ( pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV) )
+ if ( pmu_params.val & ~(XENPMU_MODE_SELF | XENPMU_MODE_HV |
+ XENPMU_MODE_ALL) )
return -EINVAL;
/* 32-bit dom0 can only sample itself. */
- if ( is_pv_32bit_vcpu(current) && (pmu_params.val & XENPMU_MODE_HV) )
+ if ( is_pv_32bit_vcpu(current) &&
+ (pmu_params.val & (XENPMU_MODE_HV | XENPMU_MODE_ALL)) )
return -EINVAL;
/*
@@ -686,7 +706,7 @@ long do_xenpmu_op(int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg)
old_mode = vpmu_mode;
vpmu_mode = pmu_params.val;
- if ( vpmu_mode == XENPMU_MODE_OFF )
+ if ( (vpmu_mode == XENPMU_MODE_OFF) || (vpmu_mode == XENPMU_MODE_ALL) )
{
/* Make sure all (non-dom0) VCPUs have unloaded their VPMUs. */
ret = vpmu_unload_all(old_mode);
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 70477b2..663b44f 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -2579,6 +2579,10 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case MSR_AMD_FAM15H_EVNTSEL0...MSR_AMD_FAM15H_PERFCTR5:
if ( vpmu_msr || (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) )
{
+ if ( (vpmu_mode & XENPMU_MODE_ALL) &&
+ !is_hardware_domain(v->domain) )
+ break;
+
if ( vpmu_do_wrmsr(regs->ecx, msr_content, 0) )
goto fail;
}
@@ -2702,6 +2706,14 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case MSR_AMD_FAM15H_EVNTSEL0...MSR_AMD_FAM15H_PERFCTR5:
if ( vpmu_msr || (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) )
{
+ if ( (vpmu_mode & XENPMU_MODE_ALL) &&
+ !is_hardware_domain(v->domain) )
+ {
+ /* Don't leak PMU MSRs to unprivileged domains */
+ regs->eax = regs->edx = 0;
+ break;
+ }
+
if ( vpmu_do_rdmsr(regs->ecx, &msr_content) )
goto fail;
diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
index db5321a..a83ae71 100644
--- a/xen/include/public/pmu.h
+++ b/xen/include/public/pmu.h
@@ -52,10 +52,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_pmu_params_t);
* - XENPMU_MODE_SELF: Guests can profile themselves
* - XENPMU_MODE_HV: Guests can profile themselves, dom0 profiles
* itself and Xen
+ * - XENPMU_MODE_ALL: Only dom0 has access to VPMU and it profiles
+ * everyone: itself, the hypervisor and the guests.
*/
#define XENPMU_MODE_OFF 0
#define XENPMU_MODE_SELF (1<<0)
#define XENPMU_MODE_HV (1<<1)
+#define XENPMU_MODE_ALL (1<<2)
/*
* PMU features:
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 22/23] x86/VPMU: NMI-based VPMU support
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (20 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 21/23] x86/VPMU: Add privileged PMU mode Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-05 21:44 ` [PATCH v17 23/23] x86/VPMU: Move VPMU files up from hvm/ directory Boris Ostrovsky
2015-01-20 10:37 ` [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Jan Beulich
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Add support for using NMIs as PMU interrupts to allow profiling hypervisor
when interrupts are disabled.
Most of processing is still performed by vpmu_do_interrupt(). However, since
certain operations are not NMI-safe we defer them to a softint that vpmu_do_interrupt()
will schedule:
* For PV guests that would be send_guest_vcpu_virq()
* For HVM guests it's VLAPIC accesses and hvm_get_segment_register() (the later
can be called in privileged profiling mode when the interrupted guest is an HVM one).
With send_guest_vcpu_virq() and hvm_get_segment_register() for PV(H) and vlapic
accesses for HVM moved to sofint, the only routines/macros that vpmu_do_interrupt()
calls in NMI mode are:
* memcpy()
* querying domain type (is_XX_domain())
* guest_cpu_user_regs()
* XLAT_cpu_user_regs()
* raise_softirq()
* vcpu_vpmu()
* vpmu_ops->arch_vpmu_save()
* vpmu_ops->do_interrupt()
The latter two only access PMU MSRs with {rd,wr}msrl() (not the _safe versions
which would not be NMI-safe).
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
docs/misc/xen-command-line.markdown | 8 +-
xen/arch/x86/hvm/svm/vpmu.c | 3 +-
xen/arch/x86/hvm/vmx/vpmu_core2.c | 3 +-
xen/arch/x86/hvm/vpmu.c | 226 ++++++++++++++++++++++++++++--------
xen/include/asm-x86/hvm/vpmu.h | 4 +-
xen/include/asm-x86/softirq.h | 3 +-
6 files changed, 192 insertions(+), 55 deletions(-)
diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 152ae03..f3d64c7 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1314,11 +1314,11 @@ Use Virtual Processor ID support if available. This prevents the need for TLB
flushes on VM entry and exit, increasing performance.
### vpmu
-> `= ( bts )`
+> `= ( [nmi,][bts] )`
> Default: `off`
-Switch on the virtualized performance monitoring unit for HVM guests.
+Switch on the virtualized performance monitoring unit.
If the current cpu isn't supported a message like
'VPMU: Initialization failed. ...'
@@ -1330,6 +1330,10 @@ wrong behaviour (see handle\_pmc\_quirk()).
If 'vpmu=bts' is specified the virtualisation of the Branch Trace Store (BTS)
feature is switched on on Intel processors supporting this feature.
+If 'vpmu=nmi' is specified the PMU interrupt will cause an NMI instead of a
+regular vector interrupt (which is the default). This can be useful for sampling
+hypervisor code that is executed with interrupts disabled.
+
*Warning:*
As the BTS virtualisation is not 100% safe and because of the nehalem quirk
don't use the vpmu flag on production systems with Intel cpus!
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
index 68113c7..7ddce33 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/hvm/svm/vpmu.c
@@ -168,7 +168,7 @@ static void amd_vpmu_unset_msr_bitmap(struct vcpu *v)
msr_bitmap_off(vpmu);
}
-static int amd_vpmu_do_interrupt(struct cpu_user_regs *regs)
+static int amd_vpmu_do_interrupt(const struct cpu_user_regs *regs)
{
return 1;
}
@@ -220,6 +220,7 @@ static inline void context_save(struct vpmu_struct *vpmu)
rdmsrl(counters[i], counter_regs[i]);
}
+/* Must be NMI-safe */
static int amd_vpmu_save(struct vpmu_struct *vpmu)
{
struct vcpu *v;
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index 8067d83..0c7fd74 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -305,6 +305,7 @@ static inline void __core2_vpmu_save(struct vpmu_struct *vpmu)
rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, core2_vpmu_cxt->global_status);
}
+/* Must be NMI-safe */
static int core2_vpmu_save(struct vpmu_struct *vpmu)
{
struct vcpu *v = vpmu_vcpu(vpmu);
@@ -720,7 +721,7 @@ static void core2_vpmu_dump(const struct vcpu *v)
}
}
-static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
+static int core2_vpmu_do_interrupt(const struct cpu_user_regs *regs)
{
struct vcpu *v = current;
u64 msr_content;
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
index ebab0f5..2ba0feb 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/hvm/vpmu.c
@@ -34,6 +34,7 @@
#include <asm/hvm/svm/svm.h>
#include <asm/hvm/svm/vmcb.h>
#include <asm/apic.h>
+#include <asm/nmi.h>
#include <public/pmu.h>
#include <xsm/xsm.h>
@@ -54,36 +55,54 @@ unsigned int __read_mostly vpmu_features = 0;
static void parse_vpmu_param(char *s);
custom_param("vpmu", parse_vpmu_param);
+static void pmu_softnmi(void);
+
static DEFINE_PER_CPU(struct vcpu *, last_vcpu);
+static DEFINE_PER_CPU(struct vcpu *, sampled_vcpu);
+
+static uint32_t __read_mostly vpmu_interrupt_type = PMU_APIC_VECTOR;
static void __init parse_vpmu_param(char *s)
{
- switch ( parse_bool(s) )
- {
- case 0:
- break;
- default:
- if ( !strcmp(s, "bts") )
- vpmu_features |= XENPMU_FEATURE_INTEL_BTS;
- else if ( *s )
+ char *ss;
+
+ vpmu_mode = XENPMU_MODE_SELF;
+ if (*s == '\0')
+ return;
+
+ do {
+ ss = strchr(s, ',');
+ if ( ss )
+ *ss = '\0';
+
+ switch ( parse_bool(s) )
{
- printk("VPMU: unknown flag: %s - vpmu disabled!\n", s);
- break;
+ default:
+ if ( !strcmp(s, "nmi") )
+ vpmu_interrupt_type = APIC_DM_NMI;
+ else if ( !strcmp(s, "bts") )
+ vpmu_features |= XENPMU_FEATURE_INTEL_BTS;
+ else
+ {
+ printk("VPMU: unknown flag: %s - vpmu disabled!\n", s);
+ case 0:
+ vpmu_mode = XENPMU_MODE_OFF;
+ case 1:
+ return;
+ }
}
- /* fall through */
- case 1:
- /* Default VPMU mode */
- vpmu_mode = XENPMU_MODE_SELF;
- break;
- }
+
+ s = ss + 1;
+ } while ( ss );
}
+
void vpmu_lvtpc_update(uint32_t val)
{
struct vcpu *curr = current;
struct vpmu_struct *vpmu = vcpu_vpmu(curr);
- vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | (val & APIC_LVT_MASKED);
+ vpmu->hw_lapic_lvtpc = vpmu_interrupt_type | (val & APIC_LVT_MASKED);
/* Postpone APIC updates for PV(H) guests if PMU interrupt is pending */
if ( is_hvm_vcpu(curr) || !vpmu->xenpmu_data ||
@@ -91,6 +110,30 @@ void vpmu_lvtpc_update(uint32_t val)
apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
}
+static void vpmu_send_interrupt(struct vcpu *v)
+{
+ struct vlapic *vlapic;
+ u32 vlapic_lvtpc;
+
+ ASSERT(is_hvm_vcpu(v));
+
+ vlapic = vcpu_vlapic(v);
+ if ( !is_vlapic_lvtpc_enabled(vlapic) )
+ return;
+
+ vlapic_lvtpc = vlapic_get_reg(vlapic, APIC_LVTPC);
+
+ switch ( GET_APIC_DELIVERY_MODE(vlapic_lvtpc) )
+ {
+ case APIC_MODE_FIXED:
+ vlapic_set_irq(vlapic, vlapic_lvtpc & APIC_VECTOR_MASK, 0);
+ break;
+ case APIC_MODE_NMI:
+ v->nmi_pending = 1;
+ break;
+ }
+}
+
int vpmu_do_msr(unsigned int msr, uint64_t *msr_content,
uint64_t supported, bool_t is_write)
{
@@ -148,7 +191,7 @@ static struct vcpu *choose_hwdom_vcpu(void)
return hardware_domain->vcpu[idx];
}
-void vpmu_do_interrupt(struct cpu_user_regs *regs)
+int vpmu_do_interrupt(const struct cpu_user_regs *regs)
{
struct vcpu *sampled = current, *sampling;
struct vpmu_struct *vpmu;
@@ -162,7 +205,7 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
{
sampling = choose_hwdom_vcpu();
if ( !sampling )
- return;
+ return 0;
}
else
sampling = sampled;
@@ -176,15 +219,15 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
uint32_t domid;
if ( !vpmu->xenpmu_data )
- return;
+ return 0;
if ( *flags & PMU_CACHED )
- return;
+ return 0;
if ( is_pvh_vcpu(sampling) &&
!(vpmu_mode & XENPMU_MODE_ALL) &&
!vpmu->arch_vpmu_ops->do_interrupt(regs) )
- return;
+ return 0;
/* PV guest will be reading PMU MSRs from xenpmu_data */
vpmu_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
@@ -251,15 +294,20 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
}
else
{
- struct segment_register seg;
-
- hvm_get_segment_register(sampled, x86_seg_cs, &seg);
- r->cs = seg.sel;
- hvm_get_segment_register(sampled, x86_seg_ss, &seg);
- r->ss = seg.sel;
- r->cpl = seg.attr.fields.dpl;
if ( !(sampled->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) )
*flags |= PMU_SAMPLE_REAL;
+
+ /* Unsafe in NMI context, defer to softint later. */
+ if ( vpmu_interrupt_type != APIC_DM_NMI )
+ {
+ struct segment_register seg;
+
+ hvm_get_segment_register(sampled, x86_seg_cs, &seg);
+ r->cs = seg.sel;
+ hvm_get_segment_register(sampled, x86_seg_ss, &seg);
+ r->ss = seg.sel;
+ r->cpl = seg.attr.fields.dpl;
+ }
}
}
@@ -271,35 +319,37 @@ void vpmu_do_interrupt(struct cpu_user_regs *regs)
vpmu->hw_lapic_lvtpc |= APIC_LVT_MASKED;
apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
- send_guest_vcpu_virq(sampling, VIRQ_XENPMU);
+ if ( vpmu_interrupt_type == APIC_DM_NMI )
+ {
+ this_cpu(sampled_vcpu) = sampled;
+ raise_softirq(PMU_SOFTIRQ);
+ }
+ else
+ send_guest_vcpu_virq(sampling, VIRQ_XENPMU);
- return;
+ return 1;
}
if ( vpmu->arch_vpmu_ops )
{
- struct vlapic *vlapic = vcpu_vlapic(sampling);
- u32 vlapic_lvtpc;
-
/* We don't support (yet) HVM dom0 */
ASSERT(sampling == sampled);
- if ( !vpmu->arch_vpmu_ops->do_interrupt(regs) ||
- !is_vlapic_lvtpc_enabled(vlapic) )
- return;
-
- vlapic_lvtpc = vlapic_get_reg(vlapic, APIC_LVTPC);
+ if ( !vpmu->arch_vpmu_ops->do_interrupt(regs) )
+ return 0;
- switch ( GET_APIC_DELIVERY_MODE(vlapic_lvtpc) )
+ if ( vpmu_interrupt_type == APIC_DM_NMI )
{
- case APIC_MODE_FIXED:
- vlapic_set_irq(vlapic, vlapic_lvtpc & APIC_VECTOR_MASK, 0);
- break;
- case APIC_MODE_NMI:
- sampling->nmi_pending = 1;
- break;
+ this_cpu(sampled_vcpu) = sampled;
+ raise_softirq(PMU_SOFTIRQ);
}
+ else
+ vpmu_send_interrupt(sampling);
+
+ return 1;
}
+
+ return 0;
}
void vpmu_do_cpuid(unsigned int input,
@@ -327,6 +377,9 @@ static void vpmu_save_force(void *arg)
vpmu_reset(vpmu, VPMU_CONTEXT_SAVE);
per_cpu(last_vcpu, smp_processor_id()) = NULL;
+
+ /* Make sure there are no outstanding PMU NMIs */
+ pmu_softnmi();
}
void vpmu_save(struct vpmu_struct *vpmu)
@@ -343,7 +396,10 @@ void vpmu_save(struct vpmu_struct *vpmu)
if ( vpmu->arch_vpmu_ops->arch_vpmu_save(vpmu) )
vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
- apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
+ apic_write(APIC_LVTPC, vpmu_interrupt_type | APIC_LVT_MASKED);
+
+ /* Make sure there are no outstanding PMU NMIs */
+ pmu_softnmi();
}
void vpmu_load(struct vpmu_struct *vpmu)
@@ -394,6 +450,9 @@ void vpmu_load(struct vpmu_struct *vpmu)
(vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED)) )
return;
+ /* Make sure there are no outstanding PMU NMIs from previous vcpu */
+ pmu_softnmi();
+
if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_load )
{
apic_write_around(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
@@ -417,7 +476,7 @@ void vpmu_initialise(struct vcpu *v)
vpmu_destroy(v);
vpmu_clear(vpmu);
vpmu->context = NULL;
- vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
+ vpmu->hw_lapic_lvtpc = vpmu_interrupt_type | APIC_LVT_MASKED;
switch ( vendor )
{
@@ -477,6 +536,55 @@ void vpmu_destroy(struct vcpu *v)
}
}
+/* Process the softirq set by PMU NMI handler */
+static void pmu_softnmi(void)
+{
+ unsigned int cpu = smp_processor_id();
+ struct vcpu *v, *sampled = per_cpu(sampled_vcpu, cpu);
+
+ if ( sampled == NULL )
+ return;
+
+ per_cpu(sampled_vcpu, cpu) = NULL;
+
+ if ( (vpmu_mode & XENPMU_MODE_ALL) ||
+ (sampled->domain->domain_id >= DOMID_FIRST_RESERVED) )
+ {
+ v = choose_hwdom_vcpu();
+ if ( !v )
+ return;
+ }
+ else
+ {
+ if ( is_hvm_vcpu(sampled) )
+ {
+ vpmu_send_interrupt(sampled);
+ return;
+ }
+ v = sampled;
+ }
+
+ if ( has_hvm_container_vcpu(sampled) )
+ {
+ struct segment_register seg;
+ struct xen_pmu_arch *pmu = &v->arch.vpmu.xenpmu_data->pmu;
+ struct xen_pmu_regs *r = &pmu->r.regs;
+
+ hvm_get_segment_register(sampled, x86_seg_cs, &seg);
+ r->cs = seg.sel;
+ hvm_get_segment_register(sampled, x86_seg_ss, &seg);
+ r->ss = seg.sel;
+ r->cpl = seg.attr.fields.dpl;
+ }
+
+ send_guest_vcpu_virq(v, VIRQ_XENPMU);
+}
+
+int pmu_nmi_interrupt(const struct cpu_user_regs *regs, int cpu)
+{
+ return vpmu_do_interrupt(regs);
+}
+
static int pvpmu_init(struct domain *d, xen_pmu_params_t *params)
{
struct vcpu *v;
@@ -793,6 +901,21 @@ static int __init vpmu_init(void)
return 0;
}
+ if ( vpmu_interrupt_type == APIC_DM_NMI )
+ {
+ if ( reserve_lapic_nmi() != 0 )
+ {
+ printk(XENLOG_WARNING "VPMU: Can't reserve NMI, will use"
+ " APIC vector 0x%x\n", PMU_APIC_VECTOR);
+ vpmu_interrupt_type = PMU_APIC_VECTOR;
+ }
+ else
+ {
+ set_nmi_callback(pmu_nmi_interrupt);
+ open_softirq(PMU_SOFTIRQ, pmu_softnmi);
+ }
+ }
+
switch ( vendor )
{
case X86_VENDOR_AMD:
@@ -810,7 +933,14 @@ static int __init vpmu_init(void)
}
if ( vpmu_mode == XENPMU_MODE_OFF )
+ {
+ if ( vpmu_interrupt_type == APIC_DM_NMI )
+ {
+ unset_nmi_callback();
+ release_lapic_nmi();
+ }
printk(XENLOG_WARNING "VPMU: Disabling due to initialization error\n");
+ }
else
printk(XENLOG_INFO "VPMU: version %s.%s\n",
__stringify(XENPMU_VER_MAJ), __stringify(XENPMU_VER_MIN));
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
index 2c888cc..ed5dc8c 100644
--- a/xen/include/asm-x86/hvm/vpmu.h
+++ b/xen/include/asm-x86/hvm/vpmu.h
@@ -53,7 +53,7 @@ struct arch_vpmu_ops {
int (*do_wrmsr)(unsigned int msr, uint64_t msr_content,
uint64_t supported);
int (*do_rdmsr)(unsigned int msr, uint64_t *msr_content);
- int (*do_interrupt)(struct cpu_user_regs *regs);
+ int (*do_interrupt)(const struct cpu_user_regs *regs);
void (*do_cpuid)(unsigned int input,
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
@@ -102,7 +102,7 @@ static inline bool_t vpmu_are_all_set(const struct vpmu_struct *vpmu,
void vpmu_lvtpc_update(uint32_t val);
int vpmu_do_msr(unsigned int msr, uint64_t *msr_content,
uint64_t supported, bool_t is_write);
-void vpmu_do_interrupt(struct cpu_user_regs *regs);
+int vpmu_do_interrupt(const struct cpu_user_regs *regs);
void vpmu_do_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
void vpmu_initialise(struct vcpu *v);
diff --git a/xen/include/asm-x86/softirq.h b/xen/include/asm-x86/softirq.h
index ec787d6..fca110f 100644
--- a/xen/include/asm-x86/softirq.h
+++ b/xen/include/asm-x86/softirq.h
@@ -8,7 +8,8 @@
#define MACHINE_CHECK_SOFTIRQ (NR_COMMON_SOFTIRQS + 3)
#define PCI_SERR_SOFTIRQ (NR_COMMON_SOFTIRQS + 4)
#define HVM_DPCI_SOFTIRQ (NR_COMMON_SOFTIRQS + 5)
-#define NR_ARCH_SOFTIRQS 6
+#define PMU_SOFTIRQ (NR_COMMON_SOFTIRQS + 6)
+#define NR_ARCH_SOFTIRQS 7
bool_t arch_skip_send_event_check(unsigned int cpu);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH v17 23/23] x86/VPMU: Move VPMU files up from hvm/ directory
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (21 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 22/23] x86/VPMU: NMI-based VPMU support Boris Ostrovsky
@ 2015-01-05 21:44 ` Boris Ostrovsky
2015-01-20 10:37 ` [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Jan Beulich
23 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-05 21:44 UTC (permalink / raw)
To: JBeulich, kevin.tian, suravee.suthikulpanit,
Aravind.Gopalakrishnan, dietmar.hahn, dgdegra
Cc: boris.ostrovsky, tim, jun.nakajima, xen-devel
Since PMU is now not HVM specific we can move VPMU-related files up from
arch/x86/hvm/ directory.
Specifically:
arch/x86/hvm/vpmu.c -> arch/x86/cpu/vpmu.c
arch/x86/hvm/svm/vpmu.c -> arch/x86/cpu/vpmu_amd.c
arch/x86/hvm/vmx/vpmu_core2.c -> arch/x86/cpu/vpmu_intel.c
include/asm-x86/hvm/vpmu.h -> include/asm-x86/vpmu.h
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
Tested-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com>
---
xen/arch/x86/cpu/Makefile | 1 +
xen/arch/x86/{hvm => cpu}/vpmu.c | 2 +-
xen/arch/x86/{hvm/svm/vpmu.c => cpu/vpmu_amd.c} | 2 +-
xen/arch/x86/{hvm/vmx/vpmu_core2.c => cpu/vpmu_intel.c} | 2 +-
xen/arch/x86/hvm/Makefile | 1 -
xen/arch/x86/hvm/svm/Makefile | 1 -
xen/arch/x86/hvm/vlapic.c | 2 +-
xen/arch/x86/hvm/vmx/Makefile | 1 -
xen/arch/x86/oprofile/op_model_ppro.c | 2 +-
xen/arch/x86/traps.c | 2 +-
xen/include/asm-x86/hvm/vmx/vmcs.h | 2 +-
xen/include/asm-x86/{hvm => }/vpmu.h | 0
12 files changed, 8 insertions(+), 10 deletions(-)
rename xen/arch/x86/{hvm => cpu}/vpmu.c (99%)
rename xen/arch/x86/{hvm/svm/vpmu.c => cpu/vpmu_amd.c} (99%)
rename xen/arch/x86/{hvm/vmx/vpmu_core2.c => cpu/vpmu_intel.c} (99%)
rename xen/include/asm-x86/{hvm => }/vpmu.h (100%)
diff --git a/xen/arch/x86/cpu/Makefile b/xen/arch/x86/cpu/Makefile
index d73d93a..74f23ae 100644
--- a/xen/arch/x86/cpu/Makefile
+++ b/xen/arch/x86/cpu/Makefile
@@ -7,3 +7,4 @@ obj-y += common.o
obj-y += intel.o
obj-y += intel_cacheinfo.o
obj-y += mwait-idle.o
+obj-y += vpmu.o vpmu_amd.o vpmu_intel.o
diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/cpu/vpmu.c
similarity index 99%
rename from xen/arch/x86/hvm/vpmu.c
rename to xen/arch/x86/cpu/vpmu.c
index 2ba0feb..4c632a9 100644
--- a/xen/arch/x86/hvm/vpmu.c
+++ b/xen/arch/x86/cpu/vpmu.c
@@ -27,10 +27,10 @@
#include <asm/types.h>
#include <asm/msr.h>
#include <asm/p2m.h>
+#include <asm/vpmu.h>
#include <asm/hvm/support.h>
#include <asm/hvm/vmx/vmx.h>
#include <asm/hvm/vmx/vmcs.h>
-#include <asm/hvm/vpmu.h>
#include <asm/hvm/svm/svm.h>
#include <asm/hvm/svm/vmcb.h>
#include <asm/apic.h>
diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/cpu/vpmu_amd.c
similarity index 99%
rename from xen/arch/x86/hvm/svm/vpmu.c
rename to xen/arch/x86/cpu/vpmu_amd.c
index 7ddce33..35b0b75 100644
--- a/xen/arch/x86/hvm/svm/vpmu.c
+++ b/xen/arch/x86/cpu/vpmu_amd.c
@@ -28,8 +28,8 @@
#include <xen/sched.h>
#include <xen/irq.h>
#include <asm/apic.h>
+#include <asm/vpmu.h>
#include <asm/hvm/vlapic.h>
-#include <asm/hvm/vpmu.h>
#include <public/pmu.h>
#define MSR_F10H_EVNTSEL_GO_SHIFT 40
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/cpu/vpmu_intel.c
similarity index 99%
rename from xen/arch/x86/hvm/vmx/vpmu_core2.c
rename to xen/arch/x86/cpu/vpmu_intel.c
index 0c7fd74..8c6349e 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/cpu/vpmu_intel.c
@@ -30,6 +30,7 @@
#include <asm/traps.h>
#include <asm/msr.h>
#include <asm/msr-index.h>
+#include <asm/vpmu.h>
#include <asm/hvm/support.h>
#include <asm/hvm/vlapic.h>
#include <asm/hvm/vmx/vmx.h>
@@ -37,7 +38,6 @@
#include <public/sched.h>
#include <public/hvm/save.h>
#include <public/pmu.h>
-#include <asm/hvm/vpmu.h>
/*
* See Intel SDM Vol 2a Instruction Set Reference chapter 3 for CPUID
diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile
index eea5555..742b83b 100644
--- a/xen/arch/x86/hvm/Makefile
+++ b/xen/arch/x86/hvm/Makefile
@@ -22,4 +22,3 @@ obj-y += vlapic.o
obj-y += vmsi.o
obj-y += vpic.o
obj-y += vpt.o
-obj-y += vpmu.o
\ No newline at end of file
diff --git a/xen/arch/x86/hvm/svm/Makefile b/xen/arch/x86/hvm/svm/Makefile
index a10a55e..760d295 100644
--- a/xen/arch/x86/hvm/svm/Makefile
+++ b/xen/arch/x86/hvm/svm/Makefile
@@ -6,4 +6,3 @@ obj-y += nestedsvm.o
obj-y += svm.o
obj-y += svmdebug.o
obj-y += vmcb.o
-obj-y += vpmu.o
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 56b9d23..9ec5da1 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -33,12 +33,12 @@
#include <asm/page.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
+#include <asm/vpmu.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
#include <asm/hvm/vmx/vmx.h>
#include <asm/hvm/nestedhvm.h>
-#include <asm/hvm/vpmu.h>
#include <public/hvm/ioreq.h>
#include <public/hvm/params.h>
diff --git a/xen/arch/x86/hvm/vmx/Makefile b/xen/arch/x86/hvm/vmx/Makefile
index 373b3d9..04a29ce 100644
--- a/xen/arch/x86/hvm/vmx/Makefile
+++ b/xen/arch/x86/hvm/vmx/Makefile
@@ -3,5 +3,4 @@ obj-y += intr.o
obj-y += realmode.o
obj-y += vmcs.o
obj-y += vmx.o
-obj-y += vpmu_core2.o
obj-y += vvmx.o
diff --git a/xen/arch/x86/oprofile/op_model_ppro.c b/xen/arch/x86/oprofile/op_model_ppro.c
index ca429a1..89649d0 100644
--- a/xen/arch/x86/oprofile/op_model_ppro.c
+++ b/xen/arch/x86/oprofile/op_model_ppro.c
@@ -19,7 +19,7 @@
#include <asm/processor.h>
#include <asm/regs.h>
#include <asm/current.h>
-#include <asm/hvm/vpmu.h>
+#include <asm/vpmu.h>
#include "op_x86_model.h"
#include "op_counter.h"
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 663b44f..33f0fc5 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -72,7 +72,7 @@
#include <asm/apic.h>
#include <asm/mc146818rtc.h>
#include <asm/hpet.h>
-#include <asm/hvm/vpmu.h>
+#include <asm/vpmu.h>
#include <public/arch-x86/cpuid.h>
#include <xsm/xsm.h>
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 5407379..237f3af 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -19,8 +19,8 @@
#ifndef __ASM_X86_HVM_VMX_VMCS_H__
#define __ASM_X86_HVM_VMX_VMCS_H__
+#include <asm/vpmu.h>
#include <asm/hvm/io.h>
-#include <asm/hvm/vpmu.h>
#include <irq_vectors.h>
extern void vmcs_dump_vcpu(struct vcpu *v);
diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/vpmu.h
similarity index 100%
rename from xen/include/asm-x86/hvm/vpmu.h
rename to xen/include/asm-x86/vpmu.h
--
1.8.1.4
^ permalink raw reply related [flat|nested] 31+ messages in thread* Re: [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support
2015-01-05 21:43 [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Boris Ostrovsky
` (22 preceding siblings ...)
2015-01-05 21:44 ` [PATCH v17 23/23] x86/VPMU: Move VPMU files up from hvm/ directory Boris Ostrovsky
@ 2015-01-20 10:37 ` Jan Beulich
2015-01-20 16:38 ` Boris Ostrovsky
23 siblings, 1 reply; 31+ messages in thread
From: Jan Beulich @ 2015-01-20 10:37 UTC (permalink / raw)
To: Boris Ostrovsky
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
>>> On 05.01.15 at 22:43, <boris.ostrovsky@oracle.com> wrote:
> Changes in v17:
> * Disable VPMU when unknown CPU vendor is detected (patch #2)
> * Remove unnecessary vendor tests in vendor-specific init routines (patch #14)
> * Remember first CPU that starts mode change and use it to stop the cycle (patch #13)
> * If vpmu ops is not present, return 0 as value for VPMU MSR read (as opposed to
> returning an error as was the case in previous patch.) (patch #18)
Any particular reason for this?
Jan
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support
2015-01-20 10:37 ` [PATCH v17 00/23] x86/PMU: Xen PMU PV(H) support Jan Beulich
@ 2015-01-20 16:38 ` Boris Ostrovsky
0 siblings, 0 replies; 31+ messages in thread
From: Boris Ostrovsky @ 2015-01-20 16:38 UTC (permalink / raw)
To: Jan Beulich
Cc: kevin.tian, suravee.suthikulpanit, tim, dietmar.hahn, xen-devel,
Aravind.Gopalakrishnan, jun.nakajima, dgdegra
On 01/20/2015 05:37 AM, Jan Beulich wrote:
>>>> On 05.01.15 at 22:43, <boris.ostrovsky@oracle.com> wrote:
>> Changes in v17:
>> * Disable VPMU when unknown CPU vendor is detected (patch #2)
>> * Remove unnecessary vendor tests in vendor-specific init routines (patch #14)
>> * Remember first CPU that starts mode change and use it to stop the cycle (patch #13)
>> * If vpmu ops is not present, return 0 as value for VPMU MSR read (as opposed to
>> returning an error as was the case in previous patch.) (patch #18)
> Any particular reason for this?
PVH guests access MSR_IA32_MISC_ENABLE early during boot, before VPMU
initialization code had a chance to run and set vpmu ops. Returning 1
from vpmu_do_msr() would result in a fatal fault.
(This change would also be consistent with what core2_no_vpmu_ops does.)
I should have explained this in the cover letter.
-boris
^ permalink raw reply [flat|nested] 31+ messages in thread