[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v13 for-xen-4.5 17/21] x86/VPMU: Handle PMU interrupts for PV guests
>>> On 03.10.14 at 23:40, <boris.ostrovsky@xxxxxxxxxx> wrote: > 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 = vcpu_vpmu(curr); > > 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); > + { > + 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. > + */ Is this btw true also when do_wrmsr() failed? Or could you not rather handle ret != 0 before the following if() (or check ret == 0 together with the other conditions)? > 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_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 0; > + > + if ( *flags & PMU_CACHED ) > + return 1; > + > + if ( is_pvh_vcpu(sampling) && > + !vpmu->arch_vpmu_ops->do_interrupt(regs) ) > + return 0; > + > + /* 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); > + vpmu_reset(vpmu, VPMU_CONTEXT_SAVE | VPMU_CONTEXT_LOADED); > + > + /* 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->eip = cur_regs->rip; > + cmp->esp = cur_regs->rsp; > + cmp->eflags = cur_regs->eflags; > + cmp->ss = cur_regs->ss; > + cmp->cs = cur_regs->cs; > + if ( (cmp->cs & 3) == 1 ) > + *flags &= ~PMU_SAMPLE_USER; > + else > + *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 ( (regs->rip >= XEN_VIRT_START) && > + (regs->rip < XEN_VIRT_END) && This is too simplistic - if sampled is a HVM domain, these address ranges in no way mean execution was in the hypervisor when the interrupt occurred. You really should be using !guest_mode() here I think. > + is_hardware_domain(sampling->domain)) > + { > + cur_regs = regs; > + domid = DOMID_XEN; > + } > + else > + cur_regs = guest_cpu_user_regs(); > + > + r->rip = cur_regs->rip; > + r->rsp = cur_regs->rsp; > + r->eflags = 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 > + *flags |= PMU_SAMPLE_USER; > + } > + else > + { > + struct segment_register seg_cs, seg_ss; Just one variable (e.g. "seg") will do. > @@ -538,6 +705,20 @@ 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; > + if ( curr->arch.vpmu.xenpmu_data == NULL ) > + return -EINVAL; Any reason you check for NULL here ... > + vpmu_lvtpc_update(curr->arch.vpmu.xenpmu_data->pmu.l.lapic_lvtpc); > + break; > + > + case XENPMU_flush: > + curr = current; > + curr->arch.vpmu.xenpmu_data->pmu.pmu_flags &= ~PMU_CACHED; ... but not before this access? Jan _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |