aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/apic.c13
-rw-r--r--xen/arch/x86/hvm/svm/svm.c8
-rw-r--r--xen/arch/x86/hvm/vmx/Makefile2
-rw-r--r--xen/arch/x86/hvm/vmx/vmx.c26
-rw-r--r--xen/arch/x86/hvm/vmx/vpmu.c119
-rw-r--r--xen/arch/x86/hvm/vmx/vpmu_core2.c469
-rw-r--r--xen/arch/x86/i8259.c1
-rw-r--r--xen/arch/x86/oprofile/op_model_ppro.c8
-rw-r--r--xen/common/xenoprof.c41
-rw-r--r--xen/include/asm-x86/hvm/hvm.h6
-rw-r--r--xen/include/asm-x86/hvm/vlapic.h6
-rw-r--r--xen/include/asm-x86/hvm/vmx/vmcs.h4
-rw-r--r--xen/include/asm-x86/hvm/vmx/vpmu.h83
-rw-r--r--xen/include/asm-x86/hvm/vmx/vpmu_core2.h68
-rw-r--r--xen/include/asm-x86/irq.h1
-rw-r--r--xen/include/asm-x86/mach-default/irq_vectors.h3
-rw-r--r--xen/include/xen/xenoprof.h6
17 files changed, 861 insertions, 3 deletions
diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c
index b64ffd2321..c3ee1bd980 100644
--- a/xen/arch/x86/apic.c
+++ b/xen/arch/x86/apic.c
@@ -94,6 +94,9 @@ void __init apic_intr_init(void)
set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+ /* Performance Counters Interrupt */
+ set_intr_gate(PMU_APIC_VECTOR, pmu_apic_interrupt);
+
/* thermal monitor LVT interrupt */
#ifdef CONFIG_X86_MCE_P4THERMAL
set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
@@ -1227,6 +1230,16 @@ fastcall void smp_error_interrupt(struct cpu_user_regs *regs)
}
/*
+ * This interrupt handles performance counters interrupt
+ */
+
+fastcall void smp_pmu_apic_interrupt(struct cpu_user_regs *regs)
+{
+ ack_APIC_irq();
+ hvm_do_pmu_interrupt(regs);
+}
+
+/*
* This initializes the IO-APIC and APIC hardware if this is
* a UP kernel.
*/
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 15ade3025d..4634be4648 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -860,6 +860,11 @@ static int svm_event_pending(struct vcpu *v)
return vmcb->eventinj.fields.v;
}
+static int svm_do_pmu_interrupt(struct cpu_user_regs *regs)
+{
+ return 0;
+}
+
static struct hvm_function_table svm_function_table = {
.name = "SVM",
.cpu_down = svm_cpu_down,
@@ -882,7 +887,8 @@ static struct hvm_function_table svm_function_table = {
.set_tsc_offset = svm_set_tsc_offset,
.inject_exception = svm_inject_exception,
.init_hypercall_page = svm_init_hypercall_page,
- .event_pending = svm_event_pending
+ .event_pending = svm_event_pending,
+ .do_pmu_interrupt = svm_do_pmu_interrupt
};
int start_svm(struct cpuinfo_x86 *c)
diff --git a/xen/arch/x86/hvm/vmx/Makefile b/xen/arch/x86/hvm/vmx/Makefile
index f315661788..691263e282 100644
--- a/xen/arch/x86/hvm/vmx/Makefile
+++ b/xen/arch/x86/hvm/vmx/Makefile
@@ -9,3 +9,5 @@ obj-y += realmode.o
endif
obj-y += vmcs.o
obj-y += vmx.o
+obj-y += vpmu.o
+obj-y += vpmu_core2.o
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 486a7bf44d..7994af937d 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -90,6 +90,8 @@ static int vmx_vcpu_initialise(struct vcpu *v)
return rc;
}
+ vpmu_initialise(v);
+
vmx_install_vlapic_mapping(v);
#ifndef VMXASSIST
@@ -104,6 +106,7 @@ static int vmx_vcpu_initialise(struct vcpu *v)
static void vmx_vcpu_destroy(struct vcpu *v)
{
vmx_destroy_vmcs(v);
+ vpmu_destroy(v);
}
#ifdef __x86_64__
@@ -742,6 +745,7 @@ static void vmx_ctxt_switch_from(struct vcpu *v)
vmx_save_guest_msrs(v);
vmx_restore_host_msrs();
vmx_save_dr(v);
+ vpmu_save(v);
}
static void vmx_ctxt_switch_to(struct vcpu *v)
@@ -752,6 +756,7 @@ static void vmx_ctxt_switch_to(struct vcpu *v)
vmx_restore_guest_msrs(v);
vmx_restore_dr(v);
+ vpmu_load(v);
}
static unsigned long vmx_get_segment_base(struct vcpu *v, enum x86_segment seg)
@@ -1119,6 +1124,11 @@ static int vmx_event_pending(struct vcpu *v)
return (__vmread(VM_ENTRY_INTR_INFO) & INTR_INFO_VALID_MASK);
}
+static int vmx_do_pmu_interrupt(struct cpu_user_regs *regs)
+{
+ return vpmu_do_interrupt(regs);
+}
+
static struct hvm_function_table vmx_function_table = {
.name = "VMX",
.domain_initialise = vmx_domain_initialise,
@@ -1141,6 +1151,7 @@ static struct hvm_function_table vmx_function_table = {
.inject_exception = vmx_inject_exception,
.init_hypercall_page = vmx_init_hypercall_page,
.event_pending = vmx_event_pending,
+ .do_pmu_interrupt = vmx_do_pmu_interrupt,
.cpu_up = vmx_cpu_up,
.cpu_down = vmx_cpu_down,
};
@@ -1300,7 +1311,6 @@ void vmx_cpuid_intercept(
case 0x00000006:
case 0x00000009:
- case 0x0000000A:
*eax = *ebx = *ecx = *edx = 0;
break;
@@ -2376,7 +2386,15 @@ static int vmx_do_msr_read(struct cpu_user_regs *regs)
/* No point in letting the guest see real MCEs */
msr_content = 0;
break;
+ case MSR_IA32_MISC_ENABLE:
+ rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
+ /* Debug Trace Store is not supported. */
+ msr_content |= MSR_IA32_MISC_ENABLE_BTS_UNAVAIL |
+ MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
+ break;
default:
+ if ( vpmu_do_rdmsr(regs) )
+ goto done;
switch ( long_mode_do_msr_read(regs) )
{
case HNDL_unhandled:
@@ -2583,6 +2601,8 @@ static int vmx_do_msr_write(struct cpu_user_regs *regs)
case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2:
goto gp_fault;
default:
+ if ( vpmu_do_wrmsr(regs) )
+ return 1;
switch ( long_mode_do_msr_write(regs) )
{
case HNDL_unhandled:
@@ -2632,6 +2652,7 @@ static void vmx_do_extint(struct cpu_user_regs *regs)
fastcall void smp_call_function_interrupt(void);
fastcall void smp_spurious_interrupt(struct cpu_user_regs *regs);
fastcall void smp_error_interrupt(struct cpu_user_regs *regs);
+ fastcall void smp_pmu_apic_interrupt(struct cpu_user_regs *regs);
#ifdef CONFIG_X86_MCE_P4THERMAL
fastcall void smp_thermal_interrupt(struct cpu_user_regs *regs);
#endif
@@ -2662,6 +2683,9 @@ static void vmx_do_extint(struct cpu_user_regs *regs)
case ERROR_APIC_VECTOR:
smp_error_interrupt(regs);
break;
+ case PMU_APIC_VECTOR:
+ smp_pmu_apic_interrupt(regs);
+ break;
#ifdef CONFIG_X86_MCE_P4THERMAL
case THERMAL_APIC_VECTOR:
smp_thermal_interrupt(regs);
diff --git a/xen/arch/x86/hvm/vmx/vpmu.c b/xen/arch/x86/hvm/vmx/vpmu.c
new file mode 100644
index 0000000000..b0f0a44501
--- /dev/null
+++ b/xen/arch/x86/hvm/vmx/vpmu.c
@@ -0,0 +1,119 @@
+/*
+ * vpmu.c: 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>
+ */
+
+#include <xen/config.h>
+#include <xen/sched.h>
+#include <asm/regs.h>
+#include <asm/types.h>
+#include <asm/msr.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/vmx/vmx.h>
+#include <asm/hvm/vmx/vmcs.h>
+#include <public/sched.h>
+#include <public/hvm/save.h>
+#include <asm/hvm/vmx/vpmu.h>
+
+int inline vpmu_do_wrmsr(struct cpu_user_regs *regs)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(current);
+
+ if ( vpmu->arch_vpmu_ops )
+ return vpmu->arch_vpmu_ops->do_wrmsr(regs);
+ return 0;
+}
+
+int inline vpmu_do_rdmsr(struct cpu_user_regs *regs)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(current);
+
+ if ( vpmu->arch_vpmu_ops )
+ return vpmu->arch_vpmu_ops->do_rdmsr(regs);
+ return 0;
+}
+
+int inline vpmu_do_interrupt(struct cpu_user_regs *regs)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(current);
+
+ if ( vpmu->arch_vpmu_ops )
+ return vpmu->arch_vpmu_ops->do_interrupt(regs);
+ return 0;
+}
+
+void vpmu_save(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+
+ if ( vpmu->arch_vpmu_ops )
+ vpmu->arch_vpmu_ops->arch_vpmu_save(v);
+}
+
+void vpmu_load(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+
+ if ( vpmu->arch_vpmu_ops )
+ vpmu->arch_vpmu_ops->arch_vpmu_load(v);
+}
+
+extern struct arch_vpmu_ops core2_vpmu_ops;
+void inline vpmu_initialise(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+
+ /* If it is not a fresh initialization, release all resources
+ * before initialise again.
+ */
+ if ( vpmu->flags & VPMU_CONTEXT_ALLOCATED )
+ vpmu_destroy(v);
+
+ if ( current_cpu_data.x86 == 6 )
+ {
+ switch ( current_cpu_data.x86_model )
+ {
+ case 15:
+ case 23:
+ vpmu->arch_vpmu_ops = &core2_vpmu_ops;
+ dprintk(XENLOG_INFO,
+ "Core 2 duo CPU detected for guest PMU usage.\n");
+ break;
+ }
+ }
+
+ if ( !vpmu->arch_vpmu_ops )
+ {
+ dprintk(XENLOG_WARNING, "Unsupport CPU model for guest PMU usage.\n");
+ return;
+ }
+
+ vpmu->flags = 0;
+ vpmu->context = NULL;
+ vpmu->arch_vpmu_ops->arch_vpmu_initialise(v);
+}
+
+void inline vpmu_destroy(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+
+ if ( vpmu->arch_vpmu_ops )
+ vpmu->arch_vpmu_ops->arch_vpmu_destroy(v);
+}
+
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
new file mode 100644
index 0000000000..4e2ebc3de2
--- /dev/null
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -0,0 +1,469 @@
+/*
+ * vpmu_core2.c: 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>
+ */
+
+#include <xen/config.h>
+#include <xen/sched.h>
+#include <asm/system.h>
+#include <asm/regs.h>
+#include <asm/types.h>
+#include <asm/msr.h>
+#include <asm/msr-index.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/vlapic.h>
+#include <asm/hvm/vmx/vmx.h>
+#include <asm/hvm/vmx/vmcs.h>
+#include <public/sched.h>
+#include <public/hvm/save.h>
+#include <asm/hvm/vmx/vpmu.h>
+#include <asm/hvm/vmx/vpmu_core2.h>
+
+static int arch_pmc_cnt = 0;
+
+static int core2_get_pmc_count(void)
+{
+ u32 eax, ebx, ecx, edx;
+
+ if ( arch_pmc_cnt )
+ return arch_pmc_cnt;
+
+ cpuid(0xa, &eax, &ebx, &ecx, &edx);
+ return arch_pmc_cnt = (eax & 0xff00) >> 8;
+}
+
+static int is_core2_vpmu_msr(u32 msr_index, int *type, int *index)
+{
+ int i;
+
+ for ( i=0; i < core2_counters.num; i++ )
+ if ( core2_counters.msr[i] == msr_index )
+ {
+ *type = MSR_TYPE_COUNTER;
+ *index = i;
+ return 1;
+ }
+ for ( i=0; i < core2_ctrls.num; i++ )
+ if ( core2_ctrls.msr[i] == msr_index )
+ {
+ *type = MSR_TYPE_CTRL;
+ *index = i;
+ 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;
+ }
+
+ if ( msr_index >= MSR_IA32_PERFCTR0 &&
+ msr_index < MSR_IA32_PERFCTR0 + core2_get_pmc_count() )
+ {
+ *type = MSR_TYPE_ARCH_COUNTER;
+ *index = msr_index - MSR_IA32_PERFCTR0;
+ return 1;
+ }
+ if ( msr_index >= MSR_P6_EVNTSEL0 &&
+ msr_index < MSR_P6_EVNTSEL0 + core2_get_pmc_count() )
+ {
+ *type = MSR_TYPE_ARCH_CTRL;
+ *index = msr_index - MSR_P6_EVNTSEL0;
+ return 1;
+ }
+ return 0;
+}
+
+static void core2_vpmu_set_msr_bitmap(char *msr_bitmap)
+{
+ int i;
+
+ /* Allow Read/Write PMU Counters MSR Directly. */
+ for ( i=0; i < core2_counters.num; i++ )
+ {
+ clear_bit(msraddr_to_bitpos(core2_counters.msr[i]), msr_bitmap);
+ clear_bit(msraddr_to_bitpos(core2_counters.msr[i]), msr_bitmap + 0x800);
+ }
+ for ( i=0; i < core2_get_pmc_count(); i++ )
+ {
+ clear_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i), msr_bitmap);
+ clear_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i), msr_bitmap + 0x800);
+ }
+ /* 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_EVNTSEL0+i), msr_bitmap);
+}
+
+static void core2_vpmu_unset_msr_bitmap(char *msr_bitmap)
+{
+ int i;
+
+ /* Undo all the changes to msr bitmap. */
+ for ( i=0; i < core2_counters.num; i++ )
+ {
+ set_bit(msraddr_to_bitpos(core2_counters.msr[i]), msr_bitmap);
+ set_bit(msraddr_to_bitpos(core2_counters.msr[i]), msr_bitmap + 0x800);
+ }
+ for ( i=0; i < core2_get_pmc_count(); i++ )
+ {
+ set_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i), msr_bitmap);
+ set_bit(msraddr_to_bitpos(MSR_IA32_PERFCTR0+i), msr_bitmap + 0x800);
+ }
+ 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++ )
+ set_bit(msraddr_to_bitpos(MSR_P6_EVNTSEL0+i), msr_bitmap);
+}
+
+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_counters.num; i++ )
+ rdmsrl(core2_counters.msr[i], core2_vpmu_cxt->counters[i]);
+ for ( i=0; i < core2_get_pmc_count(); i++ )
+ rdmsrl(MSR_IA32_PERFCTR0+i, core2_vpmu_cxt->arch_msr_pair[i].counter);
+ core2_vpmu_cxt->hw_lapic_lvtpc = apic_read(APIC_LVTPC);
+ apic_write(APIC_LVTPC, LVTPC_HVM_PMU | APIC_LVT_MASKED);
+}
+
+static void core2_vpmu_save(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+
+ if ( !((vpmu->flags & VPMU_CONTEXT_ALLOCATED) &&
+ (vpmu->flags & VPMU_CONTEXT_LOADED)) )
+ return;
+
+ __core2_vpmu_save(v);
+
+ /* Unset PMU MSR bitmap to trap lazy load. */
+ if ( !(vpmu->flags & VPMU_RUNNING) && cpu_has_vmx_msr_bitmap )
+ core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
+
+ vpmu->flags &= ~VPMU_CONTEXT_LOADED;
+ return;
+}
+
+static inline void __core2_vpmu_load(struct vcpu *v)
+{
+ int i;
+ struct core2_vpmu_context *core2_vpmu_cxt = vcpu_vpmu(v)->context;
+
+ for ( i=0; i < core2_counters.num; i++ )
+ wrmsrl(core2_counters.msr[i], core2_vpmu_cxt->counters[i]);
+ for ( i=0; i < core2_get_pmc_count(); i++ )
+ wrmsrl(MSR_IA32_PERFCTR0+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_EVNTSEL0+i, core2_vpmu_cxt->arch_msr_pair[i].control);
+
+ apic_write_around(APIC_LVTPC, core2_vpmu_cxt->hw_lapic_lvtpc);
+}
+
+static void core2_vpmu_load(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+
+ /* Only when PMU is counting, we load PMU context immediately. */
+ if ( !((vpmu->flags & VPMU_CONTEXT_ALLOCATED) &&
+ (vpmu->flags & VPMU_RUNNING)) )
+ return;
+ __core2_vpmu_load(v);
+ vpmu->flags |= VPMU_CONTEXT_LOADED;
+}
+
+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(v, MSR_CORE_PERF_GLOBAL_CTRL) )
+ return 0;
+
+ if ( vmx_add_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL) )
+ return 0;
+ vmx_write_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, -1ULL);
+
+ pmu_enable = xmalloc_bytes(sizeof(struct core2_pmu_enable) +
+ (core2_get_pmc_count()-1)*sizeof(char));
+ if ( !pmu_enable )
+ goto out1;
+ memset(pmu_enable, 0, sizeof(struct core2_pmu_enable) +
+ (core2_get_pmc_count()-1)*sizeof(char));
+
+ core2_vpmu_cxt = xmalloc_bytes(sizeof(struct core2_vpmu_context) +
+ (core2_get_pmc_count()-1)*sizeof(struct arch_msr_pair));
+ if ( !core2_vpmu_cxt )
+ goto out2;
+ memset(core2_vpmu_cxt, 0, sizeof(struct core2_vpmu_context) +
+ (core2_get_pmc_count()-1)*sizeof(struct arch_msr_pair));
+ core2_vpmu_cxt->pmu_enable = pmu_enable;
+ vpmu->context = (void *)core2_vpmu_cxt;
+
+ return 1;
+ out2:
+ xfree(pmu_enable);
+ out1:
+ dprintk(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;
+
+ 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;
+ }
+}
+
+static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(current);
+
+ if ( !is_core2_vpmu_msr(msr_index, type, index) )
+ return 0;
+
+ if ( unlikely(!(vpmu->flags & VPMU_CONTEXT_ALLOCATED)) &&
+ !core2_vpmu_alloc_resource(current) )
+ return 0;
+ vpmu->flags |= VPMU_CONTEXT_ALLOCATED;
+
+ /* Do the lazy load staff. */
+ if ( !(vpmu->flags & VPMU_CONTEXT_LOADED) )
+ {
+ __core2_vpmu_load(current);
+ vpmu->flags |= VPMU_CONTEXT_LOADED;
+ if ( cpu_has_vmx_msr_bitmap )
+ core2_vpmu_set_msr_bitmap(current->arch.hvm_vmx.msr_bitmap);
+ }
+ return 1;
+}
+
+static int core2_vpmu_do_wrmsr(struct cpu_user_regs *regs)
+{
+ u32 ecx = regs->ecx;
+ u64 msr_content, global_ctrl, non_global_ctrl;
+ char pmu_enable = 0;
+ int i, tmp;
+ int type = -1, index = -1;
+ struct vcpu *v = current;
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct core2_vpmu_context *core2_vpmu_cxt = NULL;
+
+ if ( !core2_vpmu_msr_common_check(ecx, &type, &index) )
+ return 0;
+
+ msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
+ core2_vpmu_cxt = vpmu->context;
+ switch ( ecx )
+ {
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ core2_vpmu_cxt->global_ovf_status &= ~msr_content;
+ return 1;
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ dprintk(XENLOG_INFO, "Can not write readonly MSR: \
+ MSR_PERF_GLOBAL_STATUS(0x38E)!\n");
+ vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
+ return 1;
+ case MSR_IA32_PEBS_ENABLE:
+ if ( msr_content & 1 )
+ dprintk(XENLOG_WARNING, "Guest is trying to enable PEBS, \
+ which is not supported.\n");
+ return 1;
+ case MSR_IA32_DS_AREA:
+ dprintk(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_EVNTSEL0+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 < 3; i++ )
+ {
+ 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;
+ }
+ break;
+ case MSR_CORE_PERF_FIXED_CTR_CTRL:
+ non_global_ctrl = msr_content;
+ vmx_read_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, &global_ctrl);
+ global_ctrl >>= 32;
+ for ( i = 0; i < 3; i++ )
+ {
+ 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;
+ }
+ break;
+ default:
+ tmp = ecx - MSR_P6_EVNTSEL0;
+ vmx_read_guest_msr(v, 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;
+ }
+
+ for ( i = 0; i < 3; 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];
+ if ( pmu_enable )
+ vpmu->flags |= VPMU_RUNNING;
+ else
+ vpmu->flags &= ~VPMU_RUNNING;
+
+ /* Setup LVTPC in local apic */
+ if ( vpmu->flags & VPMU_RUNNING &&
+ is_vlapic_lvtpc_enabled(vcpu_vlapic(v)) )
+ apic_write_around(APIC_LVTPC, LVTPC_HVM_PMU);
+ else
+ apic_write_around(APIC_LVTPC, LVTPC_HVM_PMU | APIC_LVT_MASKED);
+
+ core2_vpmu_save_msr_context(v, type, index, msr_content);
+ if ( type != MSR_TYPE_GLOBAL )
+ wrmsrl(ecx, msr_content);
+ else
+ vmx_write_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
+
+ return 1;
+}
+
+static int core2_vpmu_do_rdmsr(struct cpu_user_regs *regs)
+{
+ u64 msr_content = 0;
+ int type = -1, index = -1;
+ struct vcpu *v = current;
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct core2_vpmu_context *core2_vpmu_cxt = NULL;
+
+ if ( !core2_vpmu_msr_common_check(regs->ecx, &type, &index) )
+ return 0;
+
+ core2_vpmu_cxt = vpmu->context;
+ switch ( regs->ecx )
+ {
+ case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
+ break;
+ case MSR_CORE_PERF_GLOBAL_STATUS:
+ msr_content = core2_vpmu_cxt->global_ovf_status;
+ break;
+ case MSR_CORE_PERF_GLOBAL_CTRL:
+ vmx_read_guest_msr(v, MSR_CORE_PERF_GLOBAL_CTRL, &msr_content);
+ break;
+ default:
+ rdmsrl(regs->ecx, msr_content);
+ }
+
+ regs->eax = msr_content & 0xFFFFFFFF;
+ regs->edx = msr_content >> 32;
+ return 1;
+}
+
+static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
+{
+ struct vcpu *v = current;
+ u64 msr_content;
+ u32 vlapic_lvtpc;
+ unsigned char int_vec;
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct core2_vpmu_context *core2_vpmu_cxt = vpmu->context;
+ struct vlapic *vlapic = vcpu_vlapic(v);
+
+ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, msr_content);
+ if ( !msr_content )
+ return 0;
+ core2_vpmu_cxt->global_ovf_status |= msr_content;
+ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 0xC000000700000003);
+
+ apic_write_around(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
+
+ if ( !is_vlapic_lvtpc_enabled(vlapic) )
+ return 1;
+
+ vlapic_lvtpc = vlapic_get_reg(vlapic, APIC_LVTPC);
+ int_vec = vlapic_lvtpc & APIC_VECTOR_MASK;
+ vlapic_set_reg(vlapic, APIC_LVTPC, vlapic_lvtpc | APIC_LVT_MASKED);
+ if ( GET_APIC_DELIVERY_MODE(vlapic_lvtpc) == APIC_MODE_FIXED )
+ vlapic_set_irq(vcpu_vlapic(v), int_vec, 0);
+ else
+ test_and_set_bool(v->nmi_pending);
+ return 1;
+}
+
+static void core2_vpmu_initialise(struct vcpu *v)
+{
+}
+
+static void core2_vpmu_destroy(struct vcpu *v)
+{
+ struct vpmu_struct *vpmu = vcpu_vpmu(v);
+ struct core2_vpmu_context *core2_vpmu_cxt = vpmu->context;
+
+ if ( !vpmu->flags & VPMU_CONTEXT_ALLOCATED )
+ return;
+ xfree(core2_vpmu_cxt->pmu_enable);
+ xfree(vpmu->context);
+ if ( cpu_has_vmx_msr_bitmap )
+ core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
+ release_pmu_ownship(PMU_OWNER_HVM);
+}
+
+struct arch_vpmu_ops core2_vpmu_ops = {
+ .do_wrmsr = core2_vpmu_do_wrmsr,
+ .do_rdmsr = core2_vpmu_do_rdmsr,
+ .do_interrupt = core2_vpmu_do_interrupt,
+ .arch_vpmu_initialise = core2_vpmu_initialise,
+ .arch_vpmu_destroy = core2_vpmu_destroy,
+ .arch_vpmu_save = core2_vpmu_save,
+ .arch_vpmu_load = core2_vpmu_load
+};
+
diff --git a/xen/arch/x86/i8259.c b/xen/arch/x86/i8259.c
index 70eccd773a..815e9e57f3 100644
--- a/xen/arch/x86/i8259.c
+++ b/xen/arch/x86/i8259.c
@@ -72,6 +72,7 @@ BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
+BUILD_SMP_INTERRUPT(pmu_apic_interrupt,PMU_APIC_VECTOR)
BUILD_SMP_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
#define IRQ(x,y) \
diff --git a/xen/arch/x86/oprofile/op_model_ppro.c b/xen/arch/x86/oprofile/op_model_ppro.c
index 53ff2182c2..519d93104a 100644
--- a/xen/arch/x86/oprofile/op_model_ppro.c
+++ b/xen/arch/x86/oprofile/op_model_ppro.c
@@ -41,6 +41,7 @@
#define CTRL_SET_EVENT(val, e) (val |= e)
static unsigned long reset_value[NUM_COUNTERS];
+int ppro_has_global_ctrl = 0;
static void ppro_fill_in_addresses(struct op_msrs * const msrs)
{
@@ -134,6 +135,11 @@ static void ppro_start(struct op_msrs const * const msrs)
CTRL_WRITE(low, high, msrs, i);
}
}
+ /* Global Control MSR is enabled by default when system power on.
+ * However, this may not hold true when xenoprof starts to run.
+ */
+ if ( ppro_has_global_ctrl )
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, (1<<NUM_COUNTERS) - 1);
}
@@ -149,6 +155,8 @@ static void ppro_stop(struct op_msrs const * const msrs)
CTRL_SET_INACTIVE(low);
CTRL_WRITE(low, high, msrs, i);
}
+ if ( ppro_has_global_ctrl )
+ wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
}
diff --git a/xen/common/xenoprof.c b/xen/common/xenoprof.c
index 741c9f04d3..f41ebb9069 100644
--- a/xen/common/xenoprof.c
+++ b/xen/common/xenoprof.c
@@ -23,6 +23,10 @@
/* Lock protecting the following global state */
static DEFINE_SPINLOCK(xenoprof_lock);
+static DEFINE_SPINLOCK(pmu_owner_lock);
+int pmu_owner = 0;
+int pmu_hvm_refcount = 0;
+
static struct domain *active_domains[MAX_OPROF_DOMAINS];
static int active_ready[MAX_OPROF_DOMAINS];
static unsigned int adomains;
@@ -44,6 +48,37 @@ static u64 passive_samples;
static u64 idle_samples;
static u64 others_samples;
+int acquire_pmu_ownership(int pmu_ownship)
+{
+ spin_lock(&pmu_owner_lock);
+ if ( pmu_owner == PMU_OWNER_NONE )
+ {
+ pmu_owner = pmu_ownship;
+ goto out;
+ }
+
+ if ( pmu_owner == pmu_ownship )
+ goto out;
+
+ spin_unlock(&pmu_owner_lock);
+ return 0;
+ out:
+ if ( pmu_owner == PMU_OWNER_HVM )
+ pmu_hvm_refcount++;
+ spin_unlock(&pmu_owner_lock);
+ return 1;
+}
+
+void release_pmu_ownship(int pmu_ownship)
+{
+ spin_lock(&pmu_owner_lock);
+ if ( pmu_ownship == PMU_OWNER_HVM )
+ pmu_hvm_refcount--;
+ if ( !pmu_hvm_refcount )
+ pmu_owner = PMU_OWNER_NONE;
+ spin_unlock(&pmu_owner_lock);
+}
+
int is_active(struct domain *d)
{
struct xenoprof *x = d->xenoprof;
@@ -649,6 +684,11 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
break;
case XENOPROF_get_buffer:
+ if ( !acquire_pmu_ownership(PMU_OWNER_XENOPROF) )
+ {
+ ret = -EBUSY;
+ break;
+ }
ret = xenoprof_op_get_buffer(arg);
break;
@@ -786,6 +826,7 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
break;
x = current->domain->xenoprof;
unshare_xenoprof_page_with_guest(x);
+ release_pmu_ownship(PMU_OWNER_XENOPROF);
break;
}
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index fa0c2f124c..28f0d3df24 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -119,6 +119,7 @@ struct hvm_function_table {
void (*init_hypercall_page)(struct domain *d, void *hypercall_page);
int (*event_pending)(struct vcpu *v);
+ int (*do_pmu_interrupt)(struct cpu_user_regs *regs);
int (*cpu_up)(void);
void (*cpu_down)(void);
@@ -235,6 +236,11 @@ static inline int hvm_event_pending(struct vcpu *v)
return hvm_funcs.event_pending(v);
}
+static inline int hvm_do_pmu_interrupt(struct cpu_user_regs *regs)
+{
+ return hvm_funcs.do_pmu_interrupt(regs);
+}
+
/* These reserved bits in lower 32 remain 0 after any load of CR0 */
#define HVM_CR0_GUEST_RESERVED_BITS \
(~((unsigned long) \
diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h
index edefa2c055..163dcdfcc6 100644
--- a/xen/include/asm-x86/hvm/vlapic.h
+++ b/xen/include/asm-x86/hvm/vlapic.h
@@ -71,6 +71,12 @@ static inline void vlapic_set_reg(
*((uint32_t *)(&vlapic->regs->data[reg])) = val;
}
+static inline int is_vlapic_lvtpc_enabled(struct vlapic *vlapic)
+{
+ return vlapic_enabled(vlapic) &&
+ !(vlapic_get_reg(vlapic, APIC_LVTPC) & APIC_LVT_MASKED);
+}
+
int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig);
int vlapic_has_pending_irq(struct vcpu *v);
diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h
index 47ef3a9da7..2b92b30446 100644
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -22,6 +22,7 @@
#include <asm/config.h>
#include <asm/hvm/io.h>
#include <asm/hvm/vmx/cpu.h>
+#include <asm/hvm/vmx/vpmu.h>
#ifdef VMXASSIST
#include <public/hvm/vmx_assist.h>
@@ -76,6 +77,9 @@ struct arch_vmx_struct {
/* Cache of cpu execution control. */
u32 exec_control;
+ /* PMU */
+ struct vpmu_struct vpmu;
+
#ifdef __x86_64__
struct vmx_msr_state msr_state;
unsigned long shadow_gs;
diff --git a/xen/include/asm-x86/hvm/vmx/vpmu.h b/xen/include/asm-x86/hvm/vmx/vpmu.h
new file mode 100644
index 0000000000..3268e4cb04
--- /dev/null
+++ b/xen/include/asm-x86/hvm/vmx/vpmu.h
@@ -0,0 +1,83 @@
+/*
+ * vpmu.h: 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_H_
+#define __ASM_X86_HVM_VPMU_H_
+
+#define msraddr_to_bitpos(x) (((x)&0xffff) + ((x)>>31)*0x2000)
+#define vcpu_vpmu(vcpu) (&(vcpu)->arch.hvm_vcpu.u.vmx.vpmu)
+#define vpmu_vcpu(vpmu) (container_of((vpmu), struct vcpu, \
+ arch.hvm_vcpu.u.vmx.vpmu))
+#define vpmu_domain(vpmu) (vpmu_vcpu(vpmu)->domain)
+
+#define MSR_TYPE_COUNTER 0
+#define MSR_TYPE_CTRL 1
+#define MSR_TYPE_GLOBAL 2
+#define MSR_TYPE_ARCH_COUNTER 3
+#define MSR_TYPE_ARCH_CTRL 4
+
+#define LVTPC_HVM_PMU 0xf8
+
+struct pmumsr {
+ unsigned int num;
+ u32 *msr;
+};
+
+struct msr_load_store_entry {
+ u32 msr_index;
+ u32 msr_reserved;
+ u64 msr_data;
+};
+
+/* Arch specific operations shared by all vpmus */
+struct arch_vpmu_ops {
+ int (*do_wrmsr)(struct cpu_user_regs *regs);
+ int (*do_rdmsr)(struct cpu_user_regs *regs);
+ int (*do_interrupt)(struct cpu_user_regs *regs);
+ void (*arch_vpmu_initialise)(struct vcpu *v);
+ void (*arch_vpmu_destroy)(struct vcpu *v);
+ void (*arch_vpmu_save)(struct vcpu *v);
+ void (*arch_vpmu_load)(struct vcpu *v);
+};
+
+struct vpmu_struct {
+ u32 flags;
+ void *context;
+ struct arch_vpmu_ops *arch_vpmu_ops;
+};
+
+#define VPMU_CONTEXT_ALLOCATED 0x1
+#define VPMU_CONTEXT_LOADED 0x2
+#define VPMU_RUNNING 0x4
+
+int inline vpmu_do_wrmsr(struct cpu_user_regs *regs);
+int inline vpmu_do_rdmsr(struct cpu_user_regs *regs);
+int inline vpmu_do_interrupt(struct cpu_user_regs *regs);
+void inline vpmu_initialise(struct vcpu *v);
+void inline vpmu_destroy(struct vcpu *v);
+void inline vpmu_save(struct vcpu *v);
+void inline vpmu_load(struct vcpu *v);
+
+extern int acquire_pmu_ownership(int pmu_ownership);
+extern void release_pmu_ownership(int pmu_ownership);
+
+#endif /* __ASM_X86_HVM_VPMU_H_*/
+
diff --git a/xen/include/asm-x86/hvm/vmx/vpmu_core2.h b/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
new file mode 100644
index 0000000000..131675862b
--- /dev/null
+++ b/xen/include/asm-x86/hvm/vmx/vpmu_core2.h
@@ -0,0 +1,68 @@
+
+/*
+ * 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_
+
+/* Core 2 Non-architectual Performance Counter MSRs. */
+u32 core2_counters_msr[] = {
+ MSR_CORE_PERF_FIXED_CTR0,
+ MSR_CORE_PERF_FIXED_CTR1,
+ MSR_CORE_PERF_FIXED_CTR2};
+
+/* Core 2 Non-architectual Performance Control MSRs. */
+u32 core2_ctrls_msr[] = {
+ MSR_CORE_PERF_FIXED_CTR_CTRL,
+ MSR_IA32_PEBS_ENABLE,
+ MSR_IA32_DS_AREA};
+
+struct pmumsr core2_counters = {
+ 3,
+ core2_counters_msr
+};
+
+struct pmumsr core2_ctrls = {
+ 3,
+ core2_ctrls_msr
+};
+
+struct arch_msr_pair {
+ u64 counter;
+ u64 control;
+};
+
+struct core2_pmu_enable {
+ char fixed_ctr_enable[3];
+ char arch_pmc_enable[1];
+};
+
+struct core2_vpmu_context {
+ struct core2_pmu_enable *pmu_enable;
+ u64 counters[3];
+ u64 ctrls[3];
+ u64 global_ovf_status;
+ u32 hw_lapic_lvtpc;
+ struct arch_msr_pair arch_msr_pair[1];
+};
+
+#endif /* __ASM_X86_HVM_VPMU_CORE_H_ */
+
diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h
index 061c497616..e92e775945 100644
--- a/xen/include/asm-x86/irq.h
+++ b/xen/include/asm-x86/irq.h
@@ -28,6 +28,7 @@ fastcall void invalidate_interrupt(void);
fastcall void call_function_interrupt(void);
fastcall void apic_timer_interrupt(void);
fastcall void error_interrupt(void);
+fastcall void pmu_apic_interrupt(void);
fastcall void spurious_interrupt(void);
fastcall void thermal_interrupt(void);
diff --git a/xen/include/asm-x86/mach-default/irq_vectors.h b/xen/include/asm-x86/mach-default/irq_vectors.h
index 34a963a534..90b4e1ef0e 100644
--- a/xen/include/asm-x86/mach-default/irq_vectors.h
+++ b/xen/include/asm-x86/mach-default/irq_vectors.h
@@ -9,13 +9,14 @@
#define CALL_FUNCTION_VECTOR 0xfb
#define THERMAL_APIC_VECTOR 0xfa
#define LOCAL_TIMER_VECTOR 0xf9
+#define PMU_APIC_VECTOR 0xf8
/*
* High-priority dynamically-allocated vectors. For interrupts that
* must be higher priority than any guest-bound interrupt.
*/
#define FIRST_HIPRIORITY_VECTOR 0xf0
-#define LAST_HIPRIORITY_VECTOR 0xf8
+#define LAST_HIPRIORITY_VECTOR 0xf7
/* Legacy PIC uses vectors 0xe0-0xef. */
#define FIRST_LEGACY_VECTOR 0xe0
diff --git a/xen/include/xen/xenoprof.h b/xen/include/xen/xenoprof.h
index 2e47296c7c..5616d0867f 100644
--- a/xen/include/xen/xenoprof.h
+++ b/xen/include/xen/xenoprof.h
@@ -69,4 +69,10 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg);
int xenoprof_add_trace(struct domain *d, struct vcpu *v,
unsigned long eip, int mode);
+#define PMU_OWNER_NONE 0
+#define PMU_OWNER_XENOPROF 1
+#define PMU_OWNER_HVM 2
+int acquire_pmu_ownship(int pmu_ownership);
+void release_pmu_ownship(int pmu_ownership);
+
#endif /* __XEN__XENOPROF_H__ */