From patchwork Mon Sep 29 18:26:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 38105 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-la0-f72.google.com (mail-la0-f72.google.com [209.85.215.72]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 3533C201F1 for ; Mon, 29 Sep 2014 18:37:04 +0000 (UTC) Received: by mail-la0-f72.google.com with SMTP id mc6sf5746883lab.3 for ; Mon, 29 Sep 2014 11:37:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:date :message-id:in-reply-to:references:subject:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list; bh=MHlRsV857gbZW0VKi0oQTKTHxLTRAykFxlkVxSiLwOQ=; b=M7lrLrEZzYJO3ZGWz+2NPQxap6tJ/R6yaa1ndVSFQ6jKPd9YYTzs9avDs8WPjgjJev hmp4JQsRSq/h7wo2QINmpGiQ1E8wD1aMoBvi3NYg0g4yifpSEhgwcet/Smmc3msN5TeS X4+jj3paPfdDLCfBnqiwbJU0FbZ7XX/RKch9wdu8AeuSHoBpmLC6Coo7Dn45Pu/Osl9T 8yG+Zl7L+hTEtNbfwUAss4eAq0gY+K20Ce/y1WOVJl5FKX4atIcPFR7EVGtqLP0JHkqG 0aHAonXsaCOUfrrSD+MmSNZvf/+pfnry3af4l6dMNRA62umv6twdf1hR6tkJ2CZjzcKn qqxw== X-Gm-Message-State: ALoCoQll9H5qvBGgiCZaclKqeHUGHW2QfE/F8NIoUPguovovSJvlHkQfGSIAiFJA6a2VFc4FOxxW X-Received: by 10.152.3.134 with SMTP id c6mr938122lac.5.1412015823009; Mon, 29 Sep 2014 11:37:03 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.116.18 with SMTP id js18ls692586lab.69.gmail; Mon, 29 Sep 2014 11:37:02 -0700 (PDT) X-Received: by 10.112.130.168 with SMTP id of8mr39964091lbb.5.1412015822778; Mon, 29 Sep 2014 11:37:02 -0700 (PDT) Received: from mail-lb0-f174.google.com (mail-lb0-f174.google.com [209.85.217.174]) by mx.google.com with ESMTPS id 2si19382280lay.98.2014.09.29.11.37.02 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 29 Sep 2014 11:37:02 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.174 as permitted sender) client-ip=209.85.217.174; Received: by mail-lb0-f174.google.com with SMTP id p9so3326lbv.5 for ; Mon, 29 Sep 2014 11:37:02 -0700 (PDT) X-Received: by 10.152.88.16 with SMTP id bc16mr21685003lab.56.1412015822696; Mon, 29 Sep 2014 11:37:02 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.130.169 with SMTP id of9csp225710lbb; Mon, 29 Sep 2014 11:37:02 -0700 (PDT) X-Received: by 10.140.28.133 with SMTP id 5mr3029462qgz.102.1412015821557; Mon, 29 Sep 2014 11:37:01 -0700 (PDT) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id p4si14443040qcj.16.2014.09.29.11.37.00 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 29 Sep 2014 11:37:01 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Received: from localhost ([::1]:38405 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XYfoh-0007Ko-My for patch@linaro.org; Mon, 29 Sep 2014 14:36:59 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41095) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XYffF-0008JA-Qq for qemu-devel@nongnu.org; Mon, 29 Sep 2014 14:27:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XYffE-0007a8-6g for qemu-devel@nongnu.org; Mon, 29 Sep 2014 14:27:13 -0400 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:54082) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XYffD-0007L2-QT for qemu-devel@nongnu.org; Mon, 29 Sep 2014 14:27:12 -0400 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1XYfev-0005nh-MX for qemu-devel@nongnu.org; Mon, 29 Sep 2014 19:26:53 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Mon, 29 Sep 2014 19:26:35 +0100 Message-Id: <1412015213-22268-2-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1412015213-22268-1-git-send-email-peter.maydell@linaro.org> References: <1412015213-22268-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:8b0:1d0::1 Subject: [Qemu-devel] [PULL 01/19] target-arm: Implement setting guest breakpoints X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.174 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 This patch adds support for setting guest breakpoints based on values the guest writes to the DBGBVR and DBGBCR registers. (It doesn't include the code to handle when these breakpoints fire, so has no guest-visible effect.) Signed-off-by: Peter Maydell Message-id: 1410523465-13400-2-git-send-email-peter.maydell@linaro.org --- target-arm/cpu.c | 1 + target-arm/cpu.h | 1 + target-arm/helper.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++- target-arm/internals.h | 9 ++++ target-arm/machine.c | 1 + 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 407f977..6ab0e03 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -185,6 +185,7 @@ static void arm_cpu_reset(CPUState *s) } #endif + hw_breakpoint_update_all(cpu); hw_watchpoint_update_all(cpu); } diff --git a/target-arm/cpu.h b/target-arm/cpu.h index d1e1ccb..fa6ae0a 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -323,6 +323,7 @@ typedef struct CPUARMState { int eabi; #endif + struct CPUBreakpoint *cpu_breakpoint[16]; struct CPUWatchpoint *cpu_watchpoint[16]; CPU_COMMON diff --git a/target-arm/helper.c b/target-arm/helper.c index ece9673..d246d36 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2492,6 +2492,124 @@ static void dbgwcr_write(CPUARMState *env, const ARMCPRegInfo *ri, hw_watchpoint_update(cpu, i); } +void hw_breakpoint_update(ARMCPU *cpu, int n) +{ + CPUARMState *env = &cpu->env; + uint64_t bvr = env->cp15.dbgbvr[n]; + uint64_t bcr = env->cp15.dbgbcr[n]; + vaddr addr; + int bt; + int flags = BP_CPU; + + if (env->cpu_breakpoint[n]) { + cpu_breakpoint_remove_by_ref(CPU(cpu), env->cpu_breakpoint[n]); + env->cpu_breakpoint[n] = NULL; + } + + if (!extract64(bcr, 0, 1)) { + /* E bit clear : watchpoint disabled */ + return; + } + + bt = extract64(bcr, 20, 4); + + switch (bt) { + case 4: /* unlinked address mismatch (reserved if AArch64) */ + case 5: /* linked address mismatch (reserved if AArch64) */ + qemu_log_mask(LOG_UNIMP, + "arm: address mismatch breakpoint types not implemented"); + return; + case 0: /* unlinked address match */ + case 1: /* linked address match */ + { + /* Bits [63:49] are hardwired to the value of bit [48]; that is, + * we behave as if the register was sign extended. Bits [1:0] are + * RES0. The BAS field is used to allow setting breakpoints on 16 + * bit wide instructions; it is CONSTRAINED UNPREDICTABLE whether + * a bp will fire if the addresses covered by the bp and the addresses + * covered by the insn overlap but the insn doesn't start at the + * start of the bp address range. We choose to require the insn and + * the bp to have the same address. The constraints on writing to + * BAS enforced in dbgbcr_write mean we have only four cases: + * 0b0000 => no breakpoint + * 0b0011 => breakpoint on addr + * 0b1100 => breakpoint on addr + 2 + * 0b1111 => breakpoint on addr + * See also figure D2-3 in the v8 ARM ARM (DDI0487A.c). + */ + int bas = extract64(bcr, 5, 4); + addr = sextract64(bvr, 0, 49) & ~3ULL; + if (bas == 0) { + return; + } + if (bas == 0xc) { + addr += 2; + } + break; + } + case 2: /* unlinked context ID match */ + case 8: /* unlinked VMID match (reserved if no EL2) */ + case 10: /* unlinked context ID and VMID match (reserved if no EL2) */ + qemu_log_mask(LOG_UNIMP, + "arm: unlinked context breakpoint types not implemented"); + return; + case 9: /* linked VMID match (reserved if no EL2) */ + case 11: /* linked context ID and VMID match (reserved if no EL2) */ + case 3: /* linked context ID match */ + default: + /* We must generate no events for Linked context matches (unless + * they are linked to by some other bp/wp, which is handled in + * updates for the linking bp/wp). We choose to also generate no events + * for reserved values. + */ + return; + } + + cpu_breakpoint_insert(CPU(cpu), addr, flags, &env->cpu_breakpoint[n]); +} + +void hw_breakpoint_update_all(ARMCPU *cpu) +{ + int i; + CPUARMState *env = &cpu->env; + + /* Completely clear out existing QEMU breakpoints and our array, to + * avoid possible stale entries following migration load. + */ + cpu_breakpoint_remove_all(CPU(cpu), BP_CPU); + memset(env->cpu_breakpoint, 0, sizeof(env->cpu_breakpoint)); + + for (i = 0; i < ARRAY_SIZE(cpu->env.cpu_breakpoint); i++) { + hw_breakpoint_update(cpu, i); + } +} + +static void dbgbvr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + int i = ri->crm; + + raw_write(env, ri, value); + hw_breakpoint_update(cpu, i); +} + +static void dbgbcr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + int i = ri->crm; + + /* BAS[3] is a read-only copy of BAS[2], and BAS[1] a read-only + * copy of BAS[0]. + */ + value = deposit64(value, 6, 1, extract64(value, 5, 1)); + value = deposit64(value, 8, 1, extract64(value, 7, 1)); + + raw_write(env, ri, value); + hw_breakpoint_update(cpu, i); +} + static void define_debug_regs(ARMCPU *cpu) { /* Define v7 and v8 architectural debug registers. @@ -2533,11 +2651,15 @@ static void define_debug_regs(ARMCPU *cpu) { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4, .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]) }, + .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]), + .writefn = dbgbvr_write, .raw_writefn = raw_write + }, { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5, .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]) }, + .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]), + .writefn = dbgbcr_write, .raw_writefn = raw_write + }, REGINFO_SENTINEL }; define_arm_cp_regs(cpu, dbgregs); diff --git a/target-arm/internals.h b/target-arm/internals.h index 64751a0..b7e4822 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -322,6 +322,15 @@ void hw_watchpoint_update(ARMCPU *cpu, int n); * suitable for use after migration or on reset. */ void hw_watchpoint_update_all(ARMCPU *cpu); +/* Update a QEMU breakpoint based on the information the guest has set in the + * DBGBCR_EL1 and DBGBVR_EL1 registers. + */ +void hw_breakpoint_update(ARMCPU *cpu, int n); +/* Update the QEMU breakpoints for every guest breakpoint. This does a + * complete delete-and-reinstate of the QEMU breakpoint list and so is + * suitable for use after migration or on reset. + */ +void hw_breakpoint_update_all(ARMCPU *cpu); /* Callback function for when a watchpoint or breakpoint triggers. */ void arm_debug_excp_handler(CPUState *cs); diff --git a/target-arm/machine.c b/target-arm/machine.c index 8dfe87c..ddb7d05 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -214,6 +214,7 @@ static int cpu_post_load(void *opaque, int version_id) } } + hw_breakpoint_update_all(cpu); hw_watchpoint_update_all(cpu); return 0;