On 3/22/21 12:08 PM, Paolo Bonzini wrote:
On 22/03/21 19:10, Krish Sadhukhan wrote:
According to APM, the #DB intercept for a single-stepped VMRUN must
happen
after the completion of that instruction, when the guest does #VMEXIT to
the host. However, in the current implementation of KVM, the #DB
intercept
for a single-stepped VMRUN happens after the completion of the
instruction
that follows the VMRUN instruction. When the #DB intercept handler is
invoked, it shows the RIP of the instruction that follows VMRUN,
instead of
of VMRUN itself. This is an incorrect RIP as far as single-stepping
VMRUN
is concerned.
This patch fixes the problem by checking for the condtion that the VMRUN
instruction is being single-stepped and if so, triggers a synthetic #DB
intercept so that the #DB for the VMRUN is accounted for at the right
time.
Signed-off-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxxx>
---
arch/x86/kvm/svm/svm.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 58a45bb139f8..085aa02f584d 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3825,6 +3825,21 @@ static __no_kcsan fastpath_t
svm_vcpu_run(struct kvm_vcpu *vcpu)
trace_kvm_entry(vcpu);
+ if (unlikely(to_svm(vcpu)->vmcb->control.exit_code ==
SVM_EXIT_VMRUN &&
+ to_svm(vcpu)->vmcb->save.rflags & X86_EFLAGS_TF)) {
+ /*
+ * We are here following a VMRUN that is being
+ * single-stepped. The #DB intercept that is due for this
+ * single-stepping, will only be triggered when we execute
+ * the next VCPU instruction via _svm_vcpu_run(). But it
+ * will be too late. So we fake a #DB intercept by setting
+ * the appropriate exit code and returning to our caller
+ * right from here so that the due #DB can be accounted for.
+ */
+ svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + DB_VECTOR;
+ return EXIT_FASTPATH_NONE;
+ }
+
svm->vmcb->save.rax = vcpu->arch.regs[VCPU_REGS_RAX];
svm->vmcb->save.rsp = vcpu->arch.regs[VCPU_REGS_RSP];
svm->vmcb->save.rip = vcpu->arch.regs[VCPU_REGS_RIP];
Thanks for the test... Here I wonder if doing it on the nested
vmexit, and using kvm_queue_exception, would be clearer.
Doing it in nested_svm_vmexit() also works. I will send out v5. Thanks !
This VMCB patching is quite mysterious.
Paolo