|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v11 for-xen-4.5 16/20] x86/VPMU: Handle PMU interrupts for PV guests
On Tue, Sep 23, 2014 at 02:31:39PM -0400, Konrad Rzeszutek Wilk wrote:
> > int 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 0;
> > + }
> > + else
> > + sampling = sampled;
> > +
> > + vpmu = vcpu_vpmu(sampling);
> > + if ( !is_hvm_domain(sampling->domain) )
> > + {
> > + /* PV(H) guest */
> > + const struct cpu_user_regs *cur_regs;
> > +
> > + if ( !vpmu->xenpmu_data )
> > + return 0;
> > +
> > + if ( vpmu->xenpmu_data->pmu_flags & PMU_CACHED )
> > + return 1;
> > +
> > + if ( is_pvh_domain(sampled->domain) &&
> > + !vpmu->arch_vpmu_ops->do_interrupt(regs) )
> > + return 0;
> > +
> > + /* PV guest will be reading PMU MSRs from xenpmu_data */
>
> OK, with that nice comment I was thinking that:
> > + vpmu_set(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
> > + vpmu->arch_vpmu_ops->arch_vpmu_save(sampling);
>
> would be the one that writes the values to pmu.r.regs, but so far
> in this patchset that is not the case. It does write to the pmu.c (contexts)
> but that is not ..
>
> > + vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED);
> > +
> > + /* Store appropriate registers in xenpmu_data */
> > + if ( is_pv_32bit_domain(sampling->domain) )
> > + {
> > + /*
> > + * 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;
>
> .. what we read from here. Did I miss a patch?
>
> > + cmp->eip = cur_regs->rip;
> > + cmp->esp = cur_regs->rsp;
> > + cmp->cs = cur_regs->cs;
> > + if ( (cmp->cs & 3) == 1 )
> > + cmp->cs &= ~3;
> > + }
> > + else
> > + {
> > + struct xen_pmu_regs *r = &vpmu->xenpmu_data->pmu.r.regs;
>
> Ditto here.
>
> Perhaps a comment stating _who_ (or _what_) is responsible for populating
> the 'pmu.r.regs' structure?
>
> > +
> > + /* Non-privileged domains are always in XENPMU_MODE_SELF mode
> > */
> > + if ( (vpmu_mode & XENPMU_MODE_SELF) ||
> > + (!is_hardware_domain(sampled->domain) &&
> > + !is_idle_vcpu(sampled)) )
> > + cur_regs = guest_cpu_user_regs();
> > + else
> > + cur_regs = regs;
> > +
> > + r->rip = cur_regs->rip;
> > + r->rsp = cur_regs->rsp;
> > +
> > + if ( !is_pvh_domain(sampled->domain) )
> > + {
> > + r->cs = cur_regs->cs;
> > + if ( sampled->arch.flags & TF_kernel_mode )
> > + r->cs &= ~3;
> > + }
> > + else
> > + {
> > + struct segment_register seg_cs;
> > +
> > + hvm_get_segment_register(sampled, x86_seg_cs, &seg_cs);
> > + r->cs = seg_cs.sel;
> > + }
> > + }
> > +
> > + vpmu->xenpmu_data->domain_id = DOMID_SELF;
> > + vpmu->xenpmu_data->vcpu_id = sampled->vcpu_id;
> > + vpmu->xenpmu_data->pcpu_id = smp_processor_id();
> > +
> > + vpmu->xenpmu_data->pmu_flags |= PMU_CACHED;
> > + vpmu->hw_lapic_lvtpc |= APIC_LVT_MASKED;
>
> Right, especially as core2_vpmu_do_interrupt (which is called earlier)
> does:
>
> vpmu->hw_lapic_lvtpc = apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED;
> apic_write_around(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
>
> So here we mask it
>
> > + apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
>
> Hm, so for Intel we would do _two_ apic_writes ?
>
> Anyhow, we mask it here..
> .. snip..
> > case XENPMU_lvtpc_set:
> > - if ( current->arch.vpmu.xenpmu_data == NULL )
> > + curr = current;
> > + if ( curr->arch.vpmu.xenpmu_data == NULL )
> > return -EINVAL;
> > -
> > vpmu_lvtpc_update(current->arch.vpmu.xenpmu_data->pmu.l.lapic_lvtpc);
> > + vpmu_lvtpc_update(curr->arch.vpmu.xenpmu_data->pmu.l.lapic_lvtpc);
> > + ret = 0;
> > + break;
> > +
> > + case XENPMU_flush:
> > + curr = current;
> > + curr->arch.vpmu.xenpmu_data->pmu_flags &= ~PMU_CACHED;
> > + vpmu_lvtpc_update(curr->arch.vpmu.xenpmu_data->pmu.l.lapic_lvtpc);
>
> And this code does:
>
> +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);
> +}
Ignore that paste please. After I sent this I scrolled up and saw that you
had updated 'vpmu_lvtpc_update' to not do the apic_write if the PMU_CACHED
bit is set.
> +
>
> And we over-write vpmu->hw_lapic_lvtpc with the new value. The 'val'
> here is important as it may have APIC_LVT_MASKED or not. We get that
> from ' curr->arch.vpmu.xenpmu_data->pmu.l.lapic_lvtp ' but I am
> not seeing who sets it. I was thinking the XENPMU_lvtpc_set but that
> calls vpmu_lvtpc_update which will update the vpmu->hw_lapic_lvtpc
> with the APIC_LVT_MASKED if set.
>
> So who sets it?
>
> Anyhow, with it being zero, that means the APIC_LVT_MASKED is unset, so
> interrupts are free to go, and here:
>
> > + vpmu_load(curr);
>
> We do another 'apic_write_around' with the hw_lapic_lvtpc value. So two
> apci_writes to unmask it. (Or mask it back if the l.lapic_lvtpc has
> APIC_LVT_MASKED set).
>
> Should the XENPMU_flush check if:
>
> - The PMU_CACHED bit is set (and if not then -EAGAIN?)
> - The APIC_LVT_MASKED was set (and if so, then unmaks it). If it is
> not set, then no need to do apic_write?
And you patch does that already. Lets skip that question.
>
> ?
> > ret = 0;
> > break;
> > }
> > diff --git a/xen/include/public/pmu.h b/xen/include/public/pmu.h
> > index 68a5fb8..a1886a5 100644
> > --- a/xen/include/public/pmu.h
> > +++ b/xen/include/public/pmu.h
> > @@ -28,6 +28,7 @@
> > #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 */
> > @@ -61,6 +62,12 @@ DEFINE_XEN_GUEST_HANDLE(xen_pmu_params_t);
> > */
> > #define XENPMU_FEATURE_INTEL_BTS 1
> >
> > +/*
> > + * PMU MSRs are cached in the context so the PV guest doesn't need to trap
> > to
> > + * the hypervisor
> > + */
> > +#define PMU_CACHED 1
> > +
> > /* Shared between hypervisor and PV domain */
> > struct xen_pmu_data {
> > uint32_t domain_id;
> > --
> > 1.8.1.4
> >
> >
> > _______________________________________________
> > Xen-devel mailing list
> > Xen-devel@xxxxxxxxxxxxx
> > http://lists.xen.org/xen-devel
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |