Re: [PATCH] kvm: Fix perf timer mode IP reporting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 26/07/2017 02:20, Andi Kleen wrote:
> From: Andi Kleen <ak@xxxxxxxxxxxxxxx>
> 
> KVM and perf have a special backdoor mechanism to report the IP for interrupts
> re-executed after vm exit. This works for the NMIs that perf normally uses.
> 
> However when perf is in timer mode it doesn't work because the timer interrupt
> doesn't get this special treatment. This is common when KVM is running
> nested in another hypervisor which may not implement the PMU, so only
> timer mode is available.
> 
> Call the functions to set up the backdoor IP also for non NMI interrupts.
> 
> I renamed the functions to set up the backdoor IP reporting to be more
> appropiate for their new use.  The SVM change is only compile tested.
> 
> v2: Moved the functions inline.
> For the normal interrupt case the before/after functions are now
> called from x86.c, not arch specific code.

You haven't removed the code from vmx_handle_external_intr and 
svm_handle_external_intr.

> For the NMI case we still need to call it in the architecture
> specific code, because it's already needed in the low level *_run
> functions.

I must have been unclear; what I was asking is, can the calls cover
a much wider range of vcpu_enter_guest?

Like this:

        /*
         * Disable IRQs before setting IN_GUEST_MODE.  Posted interrupt
         * IPI are then delayed after guest entry, which ensures that they
         * result in virtual interrupt delivery.
         */
        local_irq_disable();
	__this_cpu_write(current_vcpu, vcpu);
        vcpu->mode = IN_GUEST_MODE;
	...
        kvm_x86_ops->handle_external_intr(vcpu);
	__this_cpu_write(current_vcpu, NULL);

This would be much cleaner and not require exporting the functions at
all to the kvm_amd and kvm_intel modules.

Thanks,

Paolo

> Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
> ---
>  arch/x86/kvm/svm.c |  6 ++++--
>  arch/x86/kvm/vmx.c |  6 ++++--
>  arch/x86/kvm/x86.c | 17 ++++-------------
>  arch/x86/kvm/x86.h | 14 ++++++++++++--
>  4 files changed, 24 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index ba9891ac5c56..41bf6a9de853 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -4872,14 +4872,14 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
>  	vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
>  
>  	if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
> -		kvm_before_handle_nmi(&svm->vcpu);
> +		kvm_before_interrupt(&svm->vcpu);
>  
>  	stgi();
>  
>  	/* Any pending NMI will happen here */
>  
>  	if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
> -		kvm_after_handle_nmi(&svm->vcpu);
> +		kvm_after_interrupt(&svm->vcpu);
>  
>  	sync_cr8_to_lapic(vcpu);
>  
> @@ -5234,6 +5234,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
>  
>  static void svm_handle_external_intr(struct kvm_vcpu *vcpu)
>  {
> +	kvm_before_interrupt(vcpu);
>  	local_irq_enable();
>  	/*
>  	 * We must have an instruction with interrupts enabled, so
> @@ -5241,6 +5242,7 @@ static void svm_handle_external_intr(struct kvm_vcpu *vcpu)
>  	 */
>  	asm("nop");
>  	local_irq_disable();
> +	kvm_after_interrupt(vcpu);
>  }
>  
>  static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index ca5d2b93385c..a02178914f6c 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -8606,9 +8606,9 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
>  
>  	/* We need to handle NMIs before interrupts are enabled */
>  	if (is_nmi(exit_intr_info)) {
> -		kvm_before_handle_nmi(&vmx->vcpu);
> +		kvm_before_interrupt(&vmx->vcpu);
>  		asm("int $2");
> -		kvm_after_handle_nmi(&vmx->vcpu);
> +		kvm_after_interrupt(&vmx->vcpu);
>  	}
>  }
>  
> @@ -8627,6 +8627,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
>  		unsigned long tmp;
>  #endif
>  
> +		kvm_before_interrupt(vcpu);
>  		vector =  exit_intr_info & INTR_INFO_VECTOR_MASK;
>  		desc = (gate_desc *)vmx->host_idt_base + vector;
>  		entry = gate_offset(*desc);
> @@ -8650,6 +8651,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
>  			[ss]"i"(__KERNEL_DS),
>  			[cs]"i"(__KERNEL_CS)
>  			);
> +		kvm_after_interrupt(vcpu);
>  	}
>  }
>  
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 0e846f0cb83b..23ed7315f294 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -5942,7 +5942,8 @@ static void kvm_timer_init(void)
>  			  kvmclock_cpu_online, kvmclock_cpu_down_prep);
>  }
>  
> -static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
> +DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
> +EXPORT_PER_CPU_SYMBOL_GPL(current_vcpu);
>  
>  int kvm_is_in_guest(void)
>  {
> @@ -5975,18 +5976,6 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
>  	.get_guest_ip		= kvm_get_guest_ip,
>  };
>  
> -void kvm_before_handle_nmi(struct kvm_vcpu *vcpu)
> -{
> -	__this_cpu_write(current_vcpu, vcpu);
> -}
> -EXPORT_SYMBOL_GPL(kvm_before_handle_nmi);
> -
> -void kvm_after_handle_nmi(struct kvm_vcpu *vcpu)
> -{
> -	__this_cpu_write(current_vcpu, NULL);
> -}
> -EXPORT_SYMBOL_GPL(kvm_after_handle_nmi);
> -
>  static void kvm_set_mmio_spte_mask(void)
>  {
>  	u64 mask;
> @@ -6963,7 +6952,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  
>  	kvm_put_guest_xcr0(vcpu);
>  
> +	kvm_before_interrupt(vcpu);
>  	kvm_x86_ops->handle_external_intr(vcpu);
> +	kvm_after_interrupt(vcpu);
>  
>  	++vcpu->stat.exits;
>  
> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
> index 612067074905..19e1b332ced8 100644
> --- a/arch/x86/kvm/x86.h
> +++ b/arch/x86/kvm/x86.h
> @@ -155,8 +155,6 @@ static inline bool kvm_check_has_quirk(struct kvm *kvm, u64 quirk)
>  	return !(kvm->arch.disabled_quirks & quirk);
>  }
>  
> -void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
> -void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
>  void kvm_set_pending_timer(struct kvm_vcpu *vcpu);
>  int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip);
>  
> @@ -248,4 +246,16 @@ static inline bool kvm_mwait_in_guest(void)
>  	return true;
>  }
>  
> +DECLARE_PER_CPU(struct kvm_vcpu *, current_vcpu);
> +
> +static inline void kvm_before_interrupt(struct kvm_vcpu *vcpu)
> +{
> +	__this_cpu_write(current_vcpu, vcpu);
> +}
> +
> +static inline void kvm_after_interrupt(struct kvm_vcpu *vcpu)
> +{
> +	__this_cpu_write(current_vcpu, NULL);
> +}
> +
>  #endif
> 




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux