@@ -994,10 +994,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);
}
@@ -1005,12 +1001,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);
@@ -885,6 +885,32 @@ int kvm_arch_put_registers(CPUState *env)
if (ret < 0)
return ret;
+ /*
+ * Kernels before 2.6.33 (which correlates with !kvm_has_vcpu_events())
+ * overwrote flags.TF injected via SET_GUEST_DEBUG while updating GP regs.
+ * Work around this by updating the debug state once again if
+ * single-stepping is on.
+ * Another reason to call kvm_update_guest_debug here is a pending debug
+ * trap raise by the guest. On kernels without SET_VCPU_EVENTS we have to
+ * reinject them via SET_GUEST_DEBUG.
+ */
+ if (!kvm_has_vcpu_events() &&
+ (env->exception_injected != -1 || env->singlestep_enabled)) {
+ unsigned long reinject_trap = 0;
+
+ if (env->exception_injected == 1) {
+ reinject_trap = KVM_GUESTDBG_INJECT_DB;
+ } else if (env->exception_injected == 3) {
+ reinject_trap = KVM_GUESTDBG_INJECT_BP;
+ }
+ env->exception_injected = -1;
+
+ ret = kvm_update_guest_debug(env, reinject_trap);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
return 0;
}
@@ -1130,10 +1156,13 @@ int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
} else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc))
handle = 1;
- if (!handle)
- kvm_update_guest_debug(cpu_single_env,
- (arch_info->exception == 1) ?
- KVM_GUESTDBG_INJECT_DB : KVM_GUESTDBG_INJECT_BP);
+ if (!handle) {
+ cpu_synchronize_state(cpu_single_env);
+ assert(cpu_single_env->exception_injected == -1);
+
+ cpu_single_env->exception_injected = arch_info->exception;
+ cpu_single_env->has_error_code = 0;
+ }
return handle;
}