From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Subject: Re: [RFC][PATCH] KVM: SVM: Defer NMI injection after IRET via interrupt Date: Mon, 15 Feb 2010 09:23:44 +0100 Message-ID: <4B790490.3040001@web.de> References: <4B783813.8000400@web.de> <20100215072055.GB19478@redhat.com> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enig20FDA96AC1195DB76E22B8D9" Cc: kvm To: Gleb Natapov Return-path: Received: from fmmailgate01.web.de ([217.72.192.221]:56756 "EHLO fmmailgate01.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751689Ab0BOIXx (ORCPT ); Mon, 15 Feb 2010 03:23:53 -0500 In-Reply-To: <20100215072055.GB19478@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig20FDA96AC1195DB76E22B8D9 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Gleb Natapov wrote: > On Sun, Feb 14, 2010 at 06:51:15PM +0100, Jan Kiszka wrote: >> From: Jan Kiszka >> >> Stolen from Xen: Instead if stepping over IRET, use the interrupt shad= ow >> to inject the NMI on IRET while still deferring its delivery after the= >> instruction. This has the same limitation as the existing approach: >> Exceptions raised by the IRET will trigger an early NMI injection. The= >> advantages are that we avoid one VM exit and we no longer have to fidd= le >> with TF which can conflict with other users. >> > Neat. I have a test case for this. I'll run it today or tomorrow and le= t > you know. Don't spend too much effort, I misunderstood the trick. It actually still requires an interrupt window exit, and that would in fact be a drawback when returning to an IRQ-disabled section. Jan >=20 >> Signed-off-by: Jan Kiszka >> --- >> >> Note: untested! >> >> arch/x86/kvm/svm.c | 40 +++++++++++++--------------------------- >> 1 files changed, 13 insertions(+), 27 deletions(-) >> >> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c >> index 52f78dd..f355dc6 100644 >> --- a/arch/x86/kvm/svm.c >> +++ b/arch/x86/kvm/svm.c >> @@ -107,8 +107,6 @@ struct vcpu_svm { >> u32 *msrpm; >> =20 >> struct nested_state nested; >> - >> - bool nmi_singlestep; >> }; >> =20 >> /* enable NPT for AMD64 and X86 with PAE */ >> @@ -1075,9 +1073,6 @@ static void update_db_intercept(struct kvm_vcpu = *vcpu) >> svm->vmcb->control.intercept_exceptions &=3D >> ~((1 << DB_VECTOR) | (1 << BP_VECTOR)); >> =20 >> - if (svm->nmi_singlestep) >> - svm->vmcb->control.intercept_exceptions |=3D (1 << DB_VECTOR); >> - >> if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { >> if (vcpu->guest_debug & >> (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) >> @@ -1213,20 +1208,11 @@ static int db_interception(struct vcpu_svm *sv= m) >> struct kvm_run *kvm_run =3D svm->vcpu.run; >> =20 >> if (!(svm->vcpu.guest_debug & >> - (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) && >> - !svm->nmi_singlestep) { >> + (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) { >> kvm_queue_exception(&svm->vcpu, DB_VECTOR); >> return 1; >> } >> =20 >> - if (svm->nmi_singlestep) { >> - svm->nmi_singlestep =3D false; >> - if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) >> - svm->vmcb->save.rflags &=3D >> - ~(X86_EFLAGS_TF | X86_EFLAGS_RF); >> - update_db_intercept(&svm->vcpu); >> - } >> - >> if (svm->vcpu.guest_debug & >> (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)){ >> kvm_run->exit_reason =3D KVM_EXIT_DEBUG; >> @@ -2471,6 +2457,17 @@ static void svm_inject_nmi(struct kvm_vcpu *vcp= u) >> { >> struct vcpu_svm *svm =3D to_svm(vcpu); >> =20 >> + if (svm->vcpu.arch.hflags & HF_IRET_MASK) { >> + /* >> + * Inject the NMI before IRET completed, but defer delivery >> + * by one instruction with the help of the interrupt shadow. >> + * Works at least as long as the IRET does not trigger an >> + * exception. >> + */ >> + svm->vcpu.arch.hflags &=3D ~HF_IRET_MASK; >> + svm->vmcb->control.int_state |=3D SVM_INTERRUPT_SHADOW_MASK; >> + } >> + >> svm->vmcb->control.event_inj =3D SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_= NMI; >> vcpu->arch.hflags |=3D HF_NMI_MASK; >> svm->vmcb->control.intercept |=3D (1UL << INTERCEPT_IRET); >> @@ -2576,18 +2573,7 @@ static void enable_irq_window(struct kvm_vcpu *= vcpu) >> =20 >> static void enable_nmi_window(struct kvm_vcpu *vcpu) >> { >> - struct vcpu_svm *svm =3D to_svm(vcpu); >> - >> - if ((svm->vcpu.arch.hflags & (HF_NMI_MASK | HF_IRET_MASK)) >> - =3D=3D HF_NMI_MASK) >> - return; /* IRET will cause a vm exit */ >> - >> - /* Something prevents NMI from been injected. Single step over >> - possible problem (IRET or exception injection or interrupt >> - shadow) */ >> - svm->nmi_singlestep =3D true; >> - svm->vmcb->save.rflags |=3D (X86_EFLAGS_TF | X86_EFLAGS_RF); >> - update_db_intercept(vcpu); >> + /* VM exit on IRET was already armed on injection */ >> } >> =20 >> static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) >> --------------enig20FDA96AC1195DB76E22B8D9 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAkt5BJcACgkQitSsb3rl5xSh/gCg0K15ZBGcCwDaG15aaeFX5Ekn ORQAoNiDeax1ytXeM40BRwaA179+LPC6 =peEY -----END PGP SIGNATURE----- --------------enig20FDA96AC1195DB76E22B8D9--