Skip to content

Commit

Permalink
target-i386: Re-introduce optimal breakpoint removal
Browse files Browse the repository at this point in the history
Before the last patch, we had an efficient loop that disabled
local breakpoints on task switch.  Re-add that, but in a more
general way that handles changes to the global enable bits too.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
  • Loading branch information
rth7680 authored and ehabkost committed Oct 23, 2015
1 parent 93d00d0 commit 36eb6e0
Showing 1 changed file with 28 additions and 6 deletions.
34 changes: 28 additions & 6 deletions target-i386/bpt_helper.c
Expand Up @@ -82,14 +82,36 @@ static void hw_breakpoint_remove(CPUX86State *env, int index)

void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7)
{
target_ulong old_dr7 = env->dr[7];
int i;

for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_remove(env, i);
}
env->dr[7] = new_dr7;
for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_insert(env, i);
/* If nothing is changing except the global/local enable bits,
then we can make the change more efficient. */
if (((old_dr7 ^ new_dr7) & ~0xff) == 0) {
/* Fold the global and local enable bits together into the
global fields, then xor to show which registers have
changed collective enable state. */
int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff;

for (i = 0; i < DR7_MAX_BP; i++) {
if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) {
hw_breakpoint_remove(env, i);
}
}
env->dr[7] = new_dr7;
for (i = 0; i < DR7_MAX_BP; i++) {
if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) {
hw_breakpoint_insert(env, i);
}
}
} else {
for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_remove(env, i);
}
env->dr[7] = new_dr7;
for (i = 0; i < DR7_MAX_BP; i++) {
hw_breakpoint_insert(env, i);
}
}
}
#endif
Expand Down

0 comments on commit 36eb6e0

Please sign in to comment.