From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49583) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZbvEN-0007m6-24 for qemu-devel@nongnu.org; Tue, 15 Sep 2015 14:45:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZbvEG-0001pF-2f for qemu-devel@nongnu.org; Tue, 15 Sep 2015 14:45:26 -0400 Received: from mail-pa0-x22e.google.com ([2607:f8b0:400e:c03::22e]:36561) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZbvEF-0001or-Ne for qemu-devel@nongnu.org; Tue, 15 Sep 2015 14:45:19 -0400 Received: by padhk3 with SMTP id hk3so183760959pad.3 for ; Tue, 15 Sep 2015 11:45:19 -0700 (PDT) Sender: Richard Henderson From: Richard Henderson Date: Tue, 15 Sep 2015 11:45:09 -0700 Message-Id: <1442342713-29497-5-git-send-email-rth@twiddle.net> In-Reply-To: <1442342713-29497-1-git-send-email-rth@twiddle.net> References: <1442342713-29497-1-git-send-email-rth@twiddle.net> Subject: [Qemu-devel] [PATCH 4/8] target-i386: Re-introduce optimal breakpoint removal List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: pbonzini@redhat.com, ehabkost@redhat.com 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 --- target-i386/bpt_helper.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/target-i386/bpt_helper.c b/target-i386/bpt_helper.c index f14788a..911d9f8 100644 --- a/target-i386/bpt_helper.c +++ b/target-i386/bpt_helper.c @@ -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)) { + /* We know that register i has changed enable state; + recheck what that state should be and apply. */ + if (hw_breakpoint_enabled(new_dr7, i)) { + hw_breakpoint_insert(env, i); + } else { + hw_breakpoint_remove(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 -- 2.1.0