From patchwork Fri Sep 12 13:23:42 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 37314 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-we0-f200.google.com (mail-we0-f200.google.com [74.125.82.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 13554203EE for ; Fri, 12 Sep 2014 13:32:09 +0000 (UTC) Received: by mail-we0-f200.google.com with SMTP id u57sf475723wes.7 for ; Fri, 12 Sep 2014 06:32:05 -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=Sc9/n/I/qR+XR36Gx/vmohLZPFvy6b2kpGYJ/+vmL5A=; b=R+9gOay0cwdF6gCShIeCbXyc/+tyXw0kegva0EyCEPWytDo1k36Eu00pu7MBsJNSv4 mI0TZCLvRusqoqYhu8Z96nNz40tNSBHYj/FURIMk147B96vfbn2yyCF9gY/2YpHHdRiO k3NliChpX2K8806zsYx0Tb/OouXnuJlJfEgomPz7uR13qpqZm2CmdJfwHXZH9BTCU3Ym EvWnfVI5TeLpDpDVv7U/PR9Kxl5KbwQQsz6uyTEN4rUqjhyg6nnEEkqH0dYsyuqpYagE qvWxqWndAhXNa0Hw2aefAcU1HoFmopNuL5pr4CZd2+S7G6vZeSIujjSB39LahEGg4mER CfzQ== X-Gm-Message-State: ALoCoQnC8vpCeXXmWvkkhUBnI4OEPLx9OuKB9VWhHGwIjgqkXAk/EcBTTT4yXcXMUSiDtWxxP6Tq X-Received: by 10.112.190.102 with SMTP id gp6mr2282134lbc.10.1410528725743; Fri, 12 Sep 2014 06:32:05 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.27.201 with SMTP id v9ls175836lag.40.gmail; Fri, 12 Sep 2014 06:32:05 -0700 (PDT) X-Received: by 10.112.56.206 with SMTP id c14mr8597422lbq.27.1410528725607; Fri, 12 Sep 2014 06:32:05 -0700 (PDT) Received: from mail-lb0-f180.google.com (mail-lb0-f180.google.com [209.85.217.180]) by mx.google.com with ESMTPS id dy7si6609412lac.28.2014.09.12.06.32.05 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 12 Sep 2014 06:32:05 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.180 as permitted sender) client-ip=209.85.217.180; Received: by mail-lb0-f180.google.com with SMTP id b12so891934lbj.39 for ; Fri, 12 Sep 2014 06:32:05 -0700 (PDT) X-Received: by 10.112.33.74 with SMTP id p10mr8610126lbi.0.1410528725541; Fri, 12 Sep 2014 06:32:05 -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.141.42 with SMTP id rl10csp732046lbb; Fri, 12 Sep 2014 06:32:04 -0700 (PDT) X-Received: by 10.229.242.65 with SMTP id lh1mr12011433qcb.18.1410528724007; Fri, 12 Sep 2014 06:32:04 -0700 (PDT) Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id x1si5631093qce.44.2014.09.12.06.32.02 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 12 Sep 2014 06:32:02 -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]:44976 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XSQxF-0004Dp-SF for patch@linaro.org; Fri, 12 Sep 2014 09:32:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56908) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XSQpX-0006pp-GH for qemu-devel@nongnu.org; Fri, 12 Sep 2014 09:24:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XSQpS-0003zC-0R for qemu-devel@nongnu.org; Fri, 12 Sep 2014 09:24:03 -0400 Received: from mnementh.archaic.org.uk ([81.2.115.146]:46961) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XSQpR-0003xi-NF for qemu-devel@nongnu.org; Fri, 12 Sep 2014 09:23:57 -0400 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1XSQpP-0003Xo-1v for qemu-devel@nongnu.org; Fri, 12 Sep 2014 14:23:55 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Fri, 12 Sep 2014 14:23:42 +0100 Message-Id: <1410528234-13545-12-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1410528234-13545-1-git-send-email-peter.maydell@linaro.org> References: <1410528234-13545-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 81.2.115.146 Subject: [Qemu-devel] [PULL 11/23] target-arm: Implement setting of watchpoints 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.180 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 Implement support for setting QEMU watchpoints based on the values the guest writes to the ARM architected watchpoint registers. (We do not yet report the firing of the watchpoints to the guest, so they will just be ignored.) Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 + target-arm/cpu.h | 2 + target-arm/helper.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++-- target-arm/internals.h | 10 ++++ target-arm/machine.c | 3 ++ 5 files changed, 149 insertions(+), 3 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index bdd23b4..6c40ecd 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -184,6 +184,8 @@ static void arm_cpu_reset(CPUState *s) kvm_arm_reset_vcpu(cpu); } #endif + + hw_watchpoint_update_all(cpu); } #ifndef CONFIG_USER_ONLY diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 51bedc8..d1e1ccb 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -323,6 +323,8 @@ typedef struct CPUARMState { int eabi; #endif + struct CPUWatchpoint *cpu_watchpoint[16]; + CPU_COMMON /* These fields after the common ones so they are preserved on reset. */ diff --git a/target-arm/helper.c b/target-arm/helper.c index 2b95f33..103dfb8 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2279,6 +2279,131 @@ static const ARMCPRegInfo debug_lpae_cp_reginfo[] = { REGINFO_SENTINEL }; +void hw_watchpoint_update(ARMCPU *cpu, int n) +{ + CPUARMState *env = &cpu->env; + vaddr len = 0; + vaddr wvr = env->cp15.dbgwvr[n]; + uint64_t wcr = env->cp15.dbgwcr[n]; + int mask; + int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; + + if (env->cpu_watchpoint[n]) { + cpu_watchpoint_remove_by_ref(CPU(cpu), env->cpu_watchpoint[n]); + env->cpu_watchpoint[n] = NULL; + } + + if (!extract64(wcr, 0, 1)) { + /* E bit clear : watchpoint disabled */ + return; + } + + switch (extract64(wcr, 3, 2)) { + case 0: + /* LSC 00 is reserved and must behave as if the wp is disabled */ + return; + case 1: + flags |= BP_MEM_READ; + break; + case 2: + flags |= BP_MEM_WRITE; + break; + case 3: + flags |= BP_MEM_ACCESS; + break; + } + + /* Attempts to use both MASK and BAS fields simultaneously are + * CONSTRAINED UNPREDICTABLE; we opt to ignore BAS in this case, + * thus generating a watchpoint for every byte in the masked region. + */ + mask = extract64(wcr, 24, 4); + if (mask == 1 || mask == 2) { + /* Reserved values of MASK; we must act as if the mask value was + * some non-reserved value, or as if the watchpoint were disabled. + * We choose the latter. + */ + return; + } else if (mask) { + /* Watchpoint covers an aligned area up to 2GB in size */ + len = 1ULL << mask; + /* If masked bits in WVR are not zero it's CONSTRAINED UNPREDICTABLE + * whether the watchpoint fires when the unmasked bits match; we opt + * to generate the exceptions. + */ + wvr &= ~(len - 1); + } else { + /* Watchpoint covers bytes defined by the byte address select bits */ + int bas = extract64(wcr, 5, 8); + int basstart; + + if (bas == 0) { + /* This must act as if the watchpoint is disabled */ + return; + } + + if (extract64(wvr, 2, 1)) { + /* Deprecated case of an only 4-aligned address. BAS[7:4] are + * ignored, and BAS[3:0] define which bytes to watch. + */ + bas &= 0xf; + } + /* The BAS bits are supposed to be programmed to indicate a contiguous + * range of bytes. Otherwise it is CONSTRAINED UNPREDICTABLE whether + * we fire for each byte in the word/doubleword addressed by the WVR. + * We choose to ignore any non-zero bits after the first range of 1s. + */ + basstart = ctz32(bas); + len = cto32(bas >> basstart); + wvr += basstart; + } + + cpu_watchpoint_insert(CPU(cpu), wvr, len, flags, + &env->cpu_watchpoint[n]); +} + +void hw_watchpoint_update_all(ARMCPU *cpu) +{ + int i; + CPUARMState *env = &cpu->env; + + /* Completely clear out existing QEMU watchpoints and our array, to + * avoid possible stale entries following migration load. + */ + cpu_watchpoint_remove_all(CPU(cpu), BP_CPU); + memset(env->cpu_watchpoint, 0, sizeof(env->cpu_watchpoint)); + + for (i = 0; i < ARRAY_SIZE(cpu->env.cpu_watchpoint); i++) { + hw_watchpoint_update(cpu, i); + } +} + +static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + int i = ri->crm; + + /* Bits [63:49] are hardwired to the value of bit [48]; that is, the + * register reads and behaves as if values written are sign extended. + * Bits [1:0] are RES0. + */ + value = sextract64(value, 0, 49) & ~3ULL; + + raw_write(env, ri, value); + hw_watchpoint_update(cpu, i); +} + +static void dbgwcr_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_watchpoint_update(cpu, i); +} + static void define_debug_regs(ARMCPU *cpu) { /* Define v7 and v8 architectural debug registers. @@ -2330,12 +2455,16 @@ static void define_debug_regs(ARMCPU *cpu) { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6, .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]) }, + .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]), + .writefn = dbgwvr_write, .raw_writefn = raw_write + }, { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH, .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7, .access = PL1_RW, - .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]) }, - REGINFO_SENTINEL + .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]), + .writefn = dbgwcr_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 53c2e3c..22f382c 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -296,4 +296,14 @@ static inline uint32_t syn_swstep(int same_el, int isv, int ex) | (isv << 24) | (ex << 6) | 0x22; } +/* Update a QEMU watchpoint based on the information the guest has set in the + * DBGWCR_EL1 and DBGWVR_EL1 registers. + */ +void hw_watchpoint_update(ARMCPU *cpu, int n); +/* Update the QEMU watchpoints for every guest watchpoint. This does a + * complete delete-and-reinstate of the QEMU watchpoint list and so is + * suitable for use after migration or on reset. + */ +void hw_watchpoint_update_all(ARMCPU *cpu); + #endif diff --git a/target-arm/machine.c b/target-arm/machine.c index 3bcc7cc..8dfe87c 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -2,6 +2,7 @@ #include "hw/boards.h" #include "sysemu/kvm.h" #include "kvm_arm.h" +#include "internals.h" static bool vfp_needed(void *opaque) { @@ -213,6 +214,8 @@ static int cpu_post_load(void *opaque, int version_id) } } + hw_watchpoint_update_all(cpu); + return 0; }