[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v21 11/14] x86/VPMU: Handle PMU interrupts for PV(H) guests
Am Freitag 08 Mai 2015, 17:06:11 schrieb Boris Ostrovsky: > Add support for handling PMU interrupts for PV(H) guests. I have only some minor nits below. Reviewed-by: Dietmar Hahn <dietmar.hahn@xxxxxxxxxxxxxx> > > 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@xxxxxxxxxx> > Acked-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> > --- > Changes in v21: > * Copy hypervisor-private VPMU context to shared page during interrupt and > copy > it back during XENPMU_flush (see also changes to patch 6). Verify > user-provided > VPMU context before loading it into hypervisor-private one (and then to HW). > Specifically, the changes are: > - Change definitions of save/load ops to take a flag that specifies whether > a copy and verification is required and, for the load op, to return error > if verification fails. > - Both load ops: update VMPU_RUNNING flag based on user-provided context, > copy > VPMU context > - Both save ops: copy VPMU context > - core2_vpmu_load(): add core2_vpmu_verify() call to do context verification > - precompute VPMU context size into ctxt_sz to use in memcpy > - Return an error in XENPMU_flush (vpmu.c) if verification fails. > * Non-privileged domains should not be provided with physical CPUID in > vpmu_do_interrupt(), set it to vcpu_id instead. > > xen/arch/x86/hvm/svm/vpmu.c | 63 +++++++--- > xen/arch/x86/hvm/vmx/vpmu_core2.c | 87 ++++++++++++-- > xen/arch/x86/hvm/vpmu.c | 237 > +++++++++++++++++++++++++++++++++++--- > xen/include/asm-x86/hvm/vpmu.h | 8 +- > xen/include/public/arch-x86/pmu.h | 3 + > xen/include/public/pmu.h | 2 + > xen/include/xsm/dummy.h | 4 +- > xen/xsm/flask/hooks.c | 2 + > 8 files changed, 359 insertions(+), 47 deletions(-) > > diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c > index 74d03a5..efe5573 100644 > --- a/xen/arch/x86/hvm/svm/vpmu.c > +++ b/xen/arch/x86/hvm/svm/vpmu.c > @@ -45,6 +45,7 @@ static unsigned int __read_mostly num_counters; > static const u32 __read_mostly *counters; > static const u32 __read_mostly *ctrls; > static bool_t __read_mostly k7_counters_mirrored; > +static unsigned long __read_mostly ctxt_sz; > > #define F10H_NUM_COUNTERS 4 > #define F15H_NUM_COUNTERS 6 > @@ -188,27 +189,52 @@ static inline void context_load(struct vcpu *v) > } > } > > -static void amd_vpmu_load(struct vcpu *v) > +static int amd_vpmu_load(struct vcpu *v, bool_t from_guest) > { > struct vpmu_struct *vpmu = vcpu_vpmu(v); > - struct xen_pmu_amd_ctxt *ctxt = vpmu->context; > - uint64_t *ctrl_regs = vpmu_reg_pointer(ctxt, ctrls); > + struct xen_pmu_amd_ctxt *ctxt; > + uint64_t *ctrl_regs; > + unsigned int i; > > vpmu_reset(vpmu, VPMU_FROZEN); > > - if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) ) > + if ( !from_guest && vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) ) > { > - unsigned int i; > + ctxt = vpmu->context; > + ctrl_regs = vpmu_reg_pointer(ctxt, ctrls); > > for ( i = 0; i < num_counters; i++ ) > wrmsrl(ctrls[i], ctrl_regs[i]); > > - return; > + return 0; > + } > + > + if ( from_guest ) > + { > + ASSERT(!is_hvm_vcpu(v)); > + > + ctxt = &vpmu->xenpmu_data->pmu.c.amd; > + ctrl_regs = vpmu_reg_pointer(ctxt, ctrls); > + for ( i = 0; i < num_counters; i++ ) > + { > + if ( is_pmu_enabled(ctrl_regs[i]) ) > + { > + vpmu_set(vpmu, VPMU_RUNNING); > + break; > + } > + } > + > + if ( i == num_counters ) > + vpmu_reset(vpmu, VPMU_RUNNING); > + > + memcpy(vpmu->context, &vpmu->xenpmu_data->pmu.c.amd, ctxt_sz); > } > > vpmu_set(vpmu, VPMU_CONTEXT_LOADED); > > context_load(v); > + > + return 0; > } > > static inline void context_save(struct vcpu *v) > @@ -223,22 +249,17 @@ 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 vcpu *v, bool_t to_guest) > { > struct vpmu_struct *vpmu = vcpu_vpmu(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; > } > > @@ -251,6 +272,12 @@ static int amd_vpmu_save(struct vcpu *v) > has_hvm_container_vcpu(v) && is_msr_bitmap_on(vpmu) ) > amd_vpmu_unset_msr_bitmap(v); > > + if ( to_guest ) > + { > + ASSERT(!is_hvm_vcpu(v)); > + memcpy(&vpmu->xenpmu_data->pmu.c.amd, vpmu->context, ctxt_sz); > + } > + > return 1; > } > > @@ -433,8 +460,7 @@ int svm_vpmu_initialise(struct vcpu *v) > if ( !counters ) > return -EINVAL; > > - ctxt = xzalloc_bytes(sizeof(*ctxt) + > - 2 * sizeof(uint64_t) * num_counters); > + ctxt = xzalloc_bytes(ctxt_sz); > if ( !ctxt ) > { > printk(XENLOG_G_WARNING "Insufficient memory for PMU, " > @@ -490,6 +516,9 @@ int __init amd_vpmu_init(void) > return -ENOSPC; > } > > + ctxt_sz = sizeof(struct xen_pmu_amd_ctxt) + > + 2 * sizeof(uint64_t) * num_counters; > + > return 0; > } > > diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c > b/xen/arch/x86/hvm/vmx/vpmu_core2.c > index 49f6771..a8df3a0 100644 > --- a/xen/arch/x86/hvm/vmx/vpmu_core2.c > +++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c > @@ -88,6 +88,9 @@ static unsigned int __read_mostly arch_pmc_cnt, > fixed_pmc_cnt; > static uint64_t __read_mostly fixed_ctrl_mask, fixed_counters_mask; > static uint64_t __read_mostly global_ovf_ctrl_mask; > > +/* VPMU context size */ > +static unsigned long __read_mostly ctxt_sz; > + > /* > * QUIRK to workaround an issue on various family 6 cpus. > * The issue leads to endless PMC interrupt loops on the processor. > @@ -310,7 +313,7 @@ static inline void __core2_vpmu_save(struct vcpu *v) > rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, core2_vpmu_cxt->global_status); > } > > -static int core2_vpmu_save(struct vcpu *v) > +static int core2_vpmu_save(struct vcpu *v, bool_t to_user) Variable name mix between core2_vpmu_save(.., to_user) and amd_vpmu_save(.., to_guest) for the same interface. > { > struct vpmu_struct *vpmu = vcpu_vpmu(v); > > @@ -327,6 +330,12 @@ static int core2_vpmu_save(struct vcpu *v) > has_hvm_container_vcpu(v) && cpu_has_vmx_msr_bitmap ) > core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap); > > + if ( to_user ) > + { > + ASSERT(!is_hvm_vcpu(v)); > + memcpy(&vpmu->xenpmu_data->pmu.c.intel, vpmu->context, ctxt_sz); > + } > + > return 1; > } > > @@ -363,16 +372,79 @@ static inline void __core2_vpmu_load(struct vcpu *v) > } > } > > -static void core2_vpmu_load(struct vcpu *v) > +static int core2_vpmu_verify(struct vcpu *v) > +{ > + unsigned int i; > + struct vpmu_struct *vpmu = vcpu_vpmu(v); > + struct xen_pmu_intel_ctxt *core2_vpmu_cxt = > + &v->arch.vpmu.xenpmu_data->pmu.c.intel; > + 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); > + uint64_t fixed_ctrl; > + uint64_t enabled_cntrs = 0; > + > + if ( core2_vpmu_cxt->global_ovf_ctrl & global_ovf_ctrl_mask ) > + return 1; > + > + fixed_ctrl = core2_vpmu_cxt->fixed_ctrl; > + if ( fixed_ctrl & fixed_ctrl_mask ) > + return 1; > + > + for ( i = 0; i < fixed_pmc_cnt; i++ ) > + { > + if ( fixed_counters[i] & fixed_counters_mask ) > + return 1; > + if ( (fixed_ctrl >> (i * FIXED_CTR_CTRL_BITS)) & 3 ) > + enabled_cntrs |= (1ULL << i); > + } > + enabled_cntrs <<= 32; > + > + for ( i = 0; i < arch_pmc_cnt; i++ ) > + { > + uint64_t control = xen_pmu_cntr_pair[i].control; > + > + if ( control & ARCH_CTRL_MASK ) > + return 1; > + if ( control & (1ULL << 22) ) As I think thats's the ENABLE bit 22 a define should be better or at least a comment? > + enabled_cntrs |= (1ULL << i); > + } > + > + if ( vpmu_is_set(vcpu_vpmu(v), VPMU_CPU_HAS_DS) && > + !is_canonical_address(core2_vpmu_cxt->ds_area) ) > + return 1; > + > + 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); > + > + *(uint64_t *)vpmu->priv_context = enabled_cntrs; > + > + return 0; > +} > + > +static int core2_vpmu_load(struct vcpu *v, bool_t from_guest) > { > struct vpmu_struct *vpmu = vcpu_vpmu(v); > > if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) ) > - return; > + return 0; > + > + if ( from_guest ) > + { > + ASSERT(!is_hvm_vcpu(v)); > + if ( core2_vpmu_verify(v) ) > + return 1; > + memcpy(vpmu->context, &v->arch.vpmu.xenpmu_data->pmu.c.intel, > ctxt_sz); > + } > > vpmu_set(vpmu, VPMU_CONTEXT_LOADED); > > __core2_vpmu_load(v); > + > + return 0; > } > > static int core2_vpmu_alloc_resource(struct vcpu *v) > @@ -395,10 +467,7 @@ static int core2_vpmu_alloc_resource(struct vcpu *v) > vmx_write_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, 0); > } > > - core2_vpmu_cxt = xzalloc_bytes(sizeof(*core2_vpmu_cxt) + > - sizeof(uint64_t) * fixed_pmc_cnt + > - sizeof(struct xen_pmu_cntr_pair) * > - arch_pmc_cnt); > + core2_vpmu_cxt = xzalloc_bytes(ctxt_sz); > p = xzalloc(uint64_t); > if ( !core2_vpmu_cxt || !p ) > goto out_err; > @@ -921,6 +990,10 @@ int __init core2_vpmu_init(void) > (((1ULL << fixed_pmc_cnt) - 1) << 32) | > ((1ULL << arch_pmc_cnt) - 1)); > > + ctxt_sz = sizeof(struct xen_pmu_intel_ctxt) + > + sizeof(uint64_t) * fixed_pmc_cnt + > + sizeof(struct xen_pmu_cntr_pair) * arch_pmc_cnt; > + > check_pmc_quirk(); > > if ( sizeof(struct xen_pmu_data) + sizeof(uint64_t) * fixed_pmc_cnt + > diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c > index 07fa368..a30f02a 100644 > --- a/xen/arch/x86/hvm/vpmu.c > +++ b/xen/arch/x86/hvm/vpmu.c > @@ -85,31 +85,56 @@ static void __init parse_vpmu_param(char *s) > void vpmu_lvtpc_update(uint32_t val) > { > struct vpmu_struct *vpmu; > + struct vcpu *curr = current; > > - if ( vpmu_mode == XENPMU_MODE_OFF ) > + if ( likely(vpmu_mode == XENPMU_MODE_OFF) ) > return; > > - vpmu = vcpu_vpmu(current); > + 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_OFF ) > 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(curr, 0); > + 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_OFF ) > { > @@ -117,24 +142,166 @@ 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(curr, 0); > + vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED); > + } > + return ret; > + } > else > *msr_content = 0; > > return 0; > } > > +static inline struct vcpu *choose_hwdom_vcpu(void) > +{ > + unsigned idx; > + > + if ( hardware_domain->max_vcpus == 0 ) > + return NULL; > + > + idx = smp_processor_id() % hardware_domain->max_vcpus; > + > + 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; > + domid_t domid = DOMID_SELF; > + > + if ( !vpmu->xenpmu_data ) > + return; > + > + if ( is_pvh_vcpu(sampling) && > + !vpmu->arch_vpmu_ops->do_interrupt(regs) ) Here you expect vpmu->arch_vpmu_ops != NULL but ... > + return; > + > + if ( *flags & PMU_CACHED ) > + 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(sampling, 1); > + 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; > + if ( is_hardware_domain(sampling->domain) ) > + vpmu->xenpmu_data->pcpu_id = smp_processor_id(); > + else > + vpmu->xenpmu_data->pcpu_id = sampled->vcpu_id; > + > + vpmu->hw_lapic_lvtpc |= APIC_LVT_MASKED; > + apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc); > + *flags |= PMU_CACHED; > + > + send_guest_vcpu_virq(sampling, VIRQ_XENPMU); > + > + return; > + } > > if ( vpmu->arch_vpmu_ops ) ... here is a check. Maybe this check here is unnecessary because you would never get this interrupt without having arch_vpmu_ops != NULL to switch on the machinery? There are some other locations too with checks before calling vpmu->arch_vpmu_ops->... and some without. Maybe it would make sense to force always a complete set of arch_vpmu_ops - functions to avoid this? > { > - 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; > @@ -147,7 +314,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; > } > } > @@ -174,7 +341,7 @@ 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); > + (void)vpmu->arch_vpmu_ops->arch_vpmu_save(v, 0); > > vpmu_reset(vpmu, VPMU_CONTEXT_SAVE); > > @@ -193,20 +360,20 @@ void vpmu_save(struct vcpu *v) > per_cpu(last_vcpu, pcpu) = v; > > if ( vpmu->arch_vpmu_ops ) > - if ( vpmu->arch_vpmu_ops->arch_vpmu_save(v) ) > + if ( vpmu->arch_vpmu_ops->arch_vpmu_save(v, 0) ) > vpmu_reset(vpmu, VPMU_CONTEXT_LOADED); > > apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED); > } > > -void vpmu_load(struct vcpu *v) > +int vpmu_load(struct vcpu *v, bool_t verify) vpmu_load uses "verify" but within the arch_vpmu_load functions (core2_vpmu_load() and amd_vpmu_load()) you use "from_guest" for the same meaning. This is a little bit confusing. Always using "verify" would be clearer I think. Dietmar. > { > struct vpmu_struct *vpmu = vcpu_vpmu(v); > int pcpu = smp_processor_id(); > struct vcpu *prev = NULL; > > if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) ) > - return; > + return 0; > > /* First time this VCPU is running here */ > if ( vpmu->last_pcpu != pcpu ) > @@ -245,15 +412,24 @@ void vpmu_load(struct vcpu *v) > local_irq_enable(); > > /* Only when PMU is counting, we load PMU context immediately. */ > - if ( !vpmu_is_set(vpmu, VPMU_RUNNING) ) > - return; > + if ( !vpmu_is_set(vpmu, VPMU_RUNNING) || > + (!is_hvm_vcpu(vpmu_vcpu(vpmu)) && > + (vpmu->xenpmu_data->pmu.pmu_flags & PMU_CACHED)) ) > + return 0; > > if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_load ) > { > 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); > + if ( vpmu->arch_vpmu_ops->arch_vpmu_load(v, verify) ) > + { > + apic_write_around(APIC_LVTPC, > + vpmu->hw_lapic_lvtpc | APIC_LVT_MASKED); > + return 1; > + } > } > + > + return 0; > } > > void vpmu_initialise(struct vcpu *v) > @@ -265,6 +441,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); > > ASSERT(!vpmu->flags && !vpmu->context); > > @@ -449,7 +627,9 @@ void vpmu_dump(struct vcpu *v) > long do_xenpmu_op(unsigned int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) > arg) > { > int ret; > + struct vcpu *curr; > struct xen_pmu_params pmu_params = {.val = 0}; > + struct xen_pmu_data *xenpmu_data; > > if ( !opt_vpmu_enabled ) > return -EOPNOTSUPP; > @@ -552,6 +732,27 @@ long do_xenpmu_op(unsigned int op, > XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg) > pvpmu_finish(current->domain, &pmu_params); > break; > > + case XENPMU_lvtpc_set: > + xenpmu_data = current->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); > + if ( vpmu_load(curr, 1) ) > + { > + xenpmu_data->pmu.pmu_flags |= PMU_CACHED; > + return -EIO; > + } > + break ; > + > default: > ret = -EINVAL; > } > diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h > index 642a4b7..564d28d 100644 > --- a/xen/include/asm-x86/hvm/vpmu.h > +++ b/xen/include/asm-x86/hvm/vpmu.h > @@ -47,8 +47,8 @@ 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 vcpu *v, bool_t to_guest); > + int (*arch_vpmu_load)(struct vcpu *v, bool_t from_guest); > void (*arch_vpmu_dump)(const struct vcpu *); > }; > > @@ -107,7 +107,7 @@ void vpmu_do_cpuid(unsigned int input, unsigned int *eax, > unsigned int *ebx, > void vpmu_initialise(struct vcpu *v); > void vpmu_destroy(struct vcpu *v); > void vpmu_save(struct vcpu *v); > -void vpmu_load(struct vcpu *v); > +int vpmu_load(struct vcpu *v, bool_t verify); > void vpmu_dump(struct vcpu *v); > > extern int acquire_pmu_ownership(int pmu_ownership); > @@ -126,7 +126,7 @@ static inline void vpmu_switch_from(struct vcpu *prev) > static inline void vpmu_switch_to(struct vcpu *next) > { > if ( vpmu_mode & (XENPMU_MODE_SELF | XENPMU_MODE_HV) ) > - vpmu_load(next); > + vpmu_load(next, 0); > } > > #endif /* __ASM_X86_HVM_VPMU_H_*/ > diff --git a/xen/include/public/arch-x86/pmu.h > b/xen/include/public/arch-x86/pmu.h > index c0068f1..de60199 100644 > --- a/xen/include/public/arch-x86/pmu.h > +++ b/xen/include/public/arch-x86/pmu.h > @@ -53,6 +53,9 @@ 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 */ > > /* > * Architecture-specific information describing state of the processor at > diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h > index 57b130b..005a2ef 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 6ec942c..e234349 100644 > --- a/xen/include/xsm/dummy.h > +++ b/xen/include/xsm/dummy.h > @@ -682,7 +682,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 f8faba8..fc0328f 100644 > --- a/xen/xsm/flask/hooks.c > +++ b/xen/xsm/flask/hooks.c > @@ -1532,6 +1532,8 @@ static int flask_pmu_op (struct domain *d, unsigned 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: > -- Company details: http://ts.fujitsu.com/imprint.html _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |