Message ID | 20230724094716.91510-5-iii@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: s390: interrupt: Fix stepping into interrupt handlers | expand |
On 24.07.23 11:44, Ilya Leoshkevich wrote: > Single-stepping a userspace-emulated instruction that generates an > interrupt causes GDB to land on the instruction following it instead of > the respective interrupt handler. > > The reason is that after arranging a KVM_EXIT_S390_SIEIC exit, > kvm_handle_sie_intercept() calls kvm_s390_handle_per_ifetch_icpt(), > which sets KVM_GUESTDBG_EXIT_PENDING. This bit, however, is not > processed immediately, but rather persists until the next ioctl(), > causing a spurious single-step exit. > > Fix by clearing this bit in ioctl(). > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > arch/s390/kvm/kvm-s390.c | 23 ++++++++++++++++++++--- > 1 file changed, 20 insertions(+), 3 deletions(-) > > diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c > index 0c6333b108ba..e6511608280c 100644 > --- a/arch/s390/kvm/kvm-s390.c > +++ b/arch/s390/kvm/kvm-s390.c > @@ -5383,6 +5383,7 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, > { > struct kvm_vcpu *vcpu = filp->private_data; > void __user *argp = (void __user *)arg; > + int rc; > > switch (ioctl) { > case KVM_S390_IRQ: { > @@ -5390,7 +5391,8 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, > > if (copy_from_user(&s390irq, argp, sizeof(s390irq))) > return -EFAULT; > - return kvm_s390_inject_vcpu(vcpu, &s390irq); > + rc = kvm_s390_inject_vcpu(vcpu, &s390irq); > + break; > } > case KVM_S390_INTERRUPT: { > struct kvm_s390_interrupt s390int; > @@ -5400,10 +5402,25 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, > return -EFAULT; > if (s390int_to_s390irq(&s390int, &s390irq)) > return -EINVAL; > - return kvm_s390_inject_vcpu(vcpu, &s390irq); > + rc = kvm_s390_inject_vcpu(vcpu, &s390irq); > + break; > } > + default: > + rc = -ENOIOCTLCMD; > + break; > } > - return -ENOIOCTLCMD; > + > + /* > + * To simplify single stepping of userspace-emulated instructions, > + * KVM_EXIT_S390_SIEIC exit sets KVM_GUESTDBG_EXIT_PENDING (see > + * should_handle_per_ifetch()). However, if userspace emulation injects > + * an interrupt, it needs to be cleared, so that KVM_EXIT_DEBUG happens > + * after (and not before) the interrupt delivery. > + */ > + if (!rc) > + vcpu->guest_debug &= ~KVM_GUESTDBG_EXIT_PENDING; > + > + return rc; > } > > static int kvm_s390_handle_pv_vcpu_dump(struct kvm_vcpu *vcpu, Reviewed-by: David Hildenbrand <david@redhat.com>
On Mon, 24 Jul 2023 11:44:10 +0200 Ilya Leoshkevich <iii@linux.ibm.com> wrote: > Single-stepping a userspace-emulated instruction that generates an > interrupt causes GDB to land on the instruction following it instead of > the respective interrupt handler. > > The reason is that after arranging a KVM_EXIT_S390_SIEIC exit, > kvm_handle_sie_intercept() calls kvm_s390_handle_per_ifetch_icpt(), > which sets KVM_GUESTDBG_EXIT_PENDING. This bit, however, is not > processed immediately, but rather persists until the next ioctl(), > causing a spurious single-step exit. > > Fix by clearing this bit in ioctl(). > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com> > --- > arch/s390/kvm/kvm-s390.c | 23 ++++++++++++++++++++--- > 1 file changed, 20 insertions(+), 3 deletions(-) > > diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c > index 0c6333b108ba..e6511608280c 100644 > --- a/arch/s390/kvm/kvm-s390.c > +++ b/arch/s390/kvm/kvm-s390.c > @@ -5383,6 +5383,7 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, > { > struct kvm_vcpu *vcpu = filp->private_data; > void __user *argp = (void __user *)arg; > + int rc; > > switch (ioctl) { > case KVM_S390_IRQ: { > @@ -5390,7 +5391,8 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, > > if (copy_from_user(&s390irq, argp, sizeof(s390irq))) > return -EFAULT; > - return kvm_s390_inject_vcpu(vcpu, &s390irq); > + rc = kvm_s390_inject_vcpu(vcpu, &s390irq); > + break; > } > case KVM_S390_INTERRUPT: { > struct kvm_s390_interrupt s390int; > @@ -5400,10 +5402,25 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, > return -EFAULT; > if (s390int_to_s390irq(&s390int, &s390irq)) > return -EINVAL; > - return kvm_s390_inject_vcpu(vcpu, &s390irq); > + rc = kvm_s390_inject_vcpu(vcpu, &s390irq); > + break; > } > + default: > + rc = -ENOIOCTLCMD; > + break; > } > - return -ENOIOCTLCMD; > + > + /* > + * To simplify single stepping of userspace-emulated instructions, > + * KVM_EXIT_S390_SIEIC exit sets KVM_GUESTDBG_EXIT_PENDING (see > + * should_handle_per_ifetch()). However, if userspace emulation injects > + * an interrupt, it needs to be cleared, so that KVM_EXIT_DEBUG happens > + * after (and not before) the interrupt delivery. > + */ > + if (!rc) > + vcpu->guest_debug &= ~KVM_GUESTDBG_EXIT_PENDING; > + > + return rc; > } > > static int kvm_s390_handle_pv_vcpu_dump(struct kvm_vcpu *vcpu,
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 0c6333b108ba..e6511608280c 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -5383,6 +5383,7 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, { struct kvm_vcpu *vcpu = filp->private_data; void __user *argp = (void __user *)arg; + int rc; switch (ioctl) { case KVM_S390_IRQ: { @@ -5390,7 +5391,8 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, if (copy_from_user(&s390irq, argp, sizeof(s390irq))) return -EFAULT; - return kvm_s390_inject_vcpu(vcpu, &s390irq); + rc = kvm_s390_inject_vcpu(vcpu, &s390irq); + break; } case KVM_S390_INTERRUPT: { struct kvm_s390_interrupt s390int; @@ -5400,10 +5402,25 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, return -EFAULT; if (s390int_to_s390irq(&s390int, &s390irq)) return -EINVAL; - return kvm_s390_inject_vcpu(vcpu, &s390irq); + rc = kvm_s390_inject_vcpu(vcpu, &s390irq); + break; } + default: + rc = -ENOIOCTLCMD; + break; } - return -ENOIOCTLCMD; + + /* + * To simplify single stepping of userspace-emulated instructions, + * KVM_EXIT_S390_SIEIC exit sets KVM_GUESTDBG_EXIT_PENDING (see + * should_handle_per_ifetch()). However, if userspace emulation injects + * an interrupt, it needs to be cleared, so that KVM_EXIT_DEBUG happens + * after (and not before) the interrupt delivery. + */ + if (!rc) + vcpu->guest_debug &= ~KVM_GUESTDBG_EXIT_PENDING; + + return rc; } static int kvm_s390_handle_pv_vcpu_dump(struct kvm_vcpu *vcpu,
Single-stepping a userspace-emulated instruction that generates an interrupt causes GDB to land on the instruction following it instead of the respective interrupt handler. The reason is that after arranging a KVM_EXIT_S390_SIEIC exit, kvm_handle_sie_intercept() calls kvm_s390_handle_per_ifetch_icpt(), which sets KVM_GUESTDBG_EXIT_PENDING. This bit, however, is not processed immediately, but rather persists until the next ioctl(), causing a spurious single-step exit. Fix by clearing this bit in ioctl(). Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- arch/s390/kvm/kvm-s390.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-)