KVM: x86: implement KVM_GUESTDBG_BLOCKIRQ
authorMaxim Levitsky <mlevitsk@redhat.com>
Wed, 11 Aug 2021 12:29:26 +0000 (15:29 +0300)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 20 Aug 2021 20:06:37 +0000 (16:06 -0400)
KVM_GUESTDBG_BLOCKIRQ will allow KVM to block all interrupts
while running.

This change is mostly intended for more robust single stepping
of the guest and it has the following benefits when enabled:

* Resuming from a breakpoint is much more reliable.
  When resuming execution from a breakpoint, with interrupts enabled,
  more often than not, KVM would inject an interrupt and make the CPU
  jump immediately to the interrupt handler and eventually return to
  the breakpoint, to trigger it again.

  From the user point of view it looks like the CPU never executed a
  single instruction and in some cases that can even prevent forward
  progress, for example, when the breakpoint is placed by an automated
  script (e.g lx-symbols), which does something in response to the
  breakpoint and then continues the guest automatically.
  If the script execution takes enough time for another interrupt to
  arrive, the guest will be stuck on the same breakpoint RIP forever.

* Normal single stepping is much more predictable, since it won't
  land the debugger into an interrupt handler.

* RFLAGS.TF has less chance to be leaked to the guest:

  We set that flag behind the guest's back to do single stepping
  but if single step lands us into an interrupt/exception handler
  it will be leaked to the guest in the form of being pushed
  to the stack.
  This doesn't completely eliminate this problem as exceptions
  can still happen, but at least this reduces the chances
  of this happening.

Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
Message-Id: <20210811122927.900604-6-mlevitsk@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Documentation/virt/kvm/api.rst
arch/x86/include/asm/kvm_host.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kvm/x86.c

index 86d7ad3a126c0b1b6e3247bb0f7b353c71023576..4ea1bb28297b4ec5584bb74cf5ad62aff10e7523 100644 (file)
@@ -3357,6 +3357,7 @@ flags which can include the following:
   - KVM_GUESTDBG_INJECT_DB:     inject DB type exception [x86]
   - KVM_GUESTDBG_INJECT_BP:     inject BP type exception [x86]
   - KVM_GUESTDBG_EXIT_PENDING:  trigger an immediate guest exit [s390]
+  - KVM_GUESTDBG_BLOCKIRQ:      avoid injecting interrupts/NMI/SMI [x86]
 
 For example KVM_GUESTDBG_USE_SW_BP indicates that software breakpoints
 are enabled in memory so we need to ensure breakpoint exceptions are
index 4c4983a9378ceb15e8412df614d05d3f67b85e58..7723865077fdc0a054b68a6c4bebc9433512a2a7 100644 (file)
@@ -222,7 +222,8 @@ enum x86_intercept_stage;
        KVM_GUESTDBG_USE_HW_BP | \
        KVM_GUESTDBG_USE_SW_BP | \
        KVM_GUESTDBG_INJECT_BP | \
-       KVM_GUESTDBG_INJECT_DB)
+       KVM_GUESTDBG_INJECT_DB | \
+       KVM_GUESTDBG_BLOCKIRQ)
 
 
 #define PFERR_PRESENT_BIT 0
index a6c327f8ad9e5f079dd7039229e3df7e296fc345..2ef1f6513c68e30b473f15f905557ba83245d22c 100644 (file)
@@ -295,6 +295,7 @@ struct kvm_debug_exit_arch {
 #define KVM_GUESTDBG_USE_HW_BP         0x00020000
 #define KVM_GUESTDBG_INJECT_DB         0x00040000
 #define KVM_GUESTDBG_INJECT_BP         0x00080000
+#define KVM_GUESTDBG_BLOCKIRQ          0x00100000
 
 /* for KVM_SET_GUEST_DEBUG */
 struct kvm_guest_debug_arch {
index 4e07cae5663605e0ba5b010f79fb5c4a7eda6a8c..1a00af1b076b6d8dfc1dbba20a4d09350c22e9ae 100644 (file)
@@ -8892,6 +8892,10 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit)
                can_inject = false;
        }
 
+       /* Don't inject interrupts if the user asked to avoid doing so */
+       if (vcpu->guest_debug & KVM_GUESTDBG_BLOCKIRQ)
+               return 0;
+
        /*
         * Finally, inject interrupt events.  If an event cannot be injected
         * due to architectural conditions (e.g. IF=0) a window-open exit