[PATCH 11/21] KVM: Rework of guest debug state writing

Jan Kiszka
2010-02-02T08:19:44Z

So far we synchronized any dirty VCPU state back into the kernel before
updating the guest debug state. This was a tribute to a deficite in x86
kernels before 2.6.33. But as this is an arch-dependent issue, it is
better handle in the x86 part of KVM and remove the writeback point for
generic code.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
kvm-all.c | 12 ++++--------
target-i386/cpu.h | 9 ++++++++-
target-i386/kvm.c | 11 +++++++++++
3 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index 3516f01..9c921cc 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -951,10 +951,6 @@ static void kvm_invoke_set_guest_debug(void *data)
struct kvm_set_guest_debug_data *dbg_data = data;
CPUState *env = dbg_data->env;

- if (env->kvm_vcpu_dirty) {
- kvm_arch_put_registers(env);
- env->kvm_vcpu_dirty = 0;
- }
dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg);
}

@@ -962,12 +958,12 @@ int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
{
struct kvm_set_guest_debug_data data;

- data.dbg.control = 0;
- if (env->singlestep_enabled)
- data.dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+ data.dbg.control = reinject_trap;

+ if (env->singlestep_enabled) {
+ data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+ }
kvm_arch_update_guest_debug(env, &data.dbg);
- data.dbg.control |= reinject_trap;
data.env = env;

on_vcpu(env, kvm_invoke_set_guest_debug, &data);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 7d0bbd0..7787fb1 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -21,6 +21,10 @@

#include "config.h"

+#ifdef CONFIG_KVM
+#include <linux/kvm.h> /* for kvm_guest_debug */
+#endif
+
#ifdef TARGET_X86_64
#define TARGET_LONG_BITS 64
#else
@@ -718,7 +722,10 @@ typedef struct CPUX86State {
uint8_t has_error_code;
uint32_t sipi_vector;
uint32_t cpuid_kvm_features;
-
+#if defined(CONFIG_KVM) && defined(KVM_CAP_SET_GUEST_DEBUG)
+ struct kvm_guest_debug kvm_guest_debug;
+#endif
+
/* in order to simplify APIC support, we leave this pointer to the
user */
struct APICState *apic_state;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 8743f32..5ac12a8 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -865,6 +865,15 @@ int kvm_arch_put_registers(CPUState *env)
if (ret < 0)
return ret;

+ /*
+ * Kernels before 2.6.33 overwrote flags.TF injected via SET_GUEST_DEBUG
+ * while updating GP regs. Work around this by updating the debug state
+ * once again.
+ */
+ ret = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &env->kvm_guest_debug);
+ if (ret < 0)
+ return ret;
+
ret = kvm_put_fpu(env);
if (ret < 0)
return ret;
@@ -1163,6 +1172,8 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
(len_code[hw_breakpoint[n].len] << (18 + n*4));
}
}
+ /* Keep a copy for the writeback workaround in kvm_arch_put_registers */
+ memcpy(&env->kvm_guest_debug, dbg, sizeof(env->kvm_guest_debug));
}
#endif /* KVM_CAP_SET_GUEST_DEBUG */
#endif
--
1.6.0.2