[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 01/19] target-arm: Implement setting guest breakpoint
From: |
Peter Maydell |
Subject: |
[Qemu-devel] [PULL 01/19] target-arm: Implement setting guest breakpoints |
Date: |
Mon, 29 Sep 2014 19:26:35 +0100 |
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 <address@hidden>
Message-id: address@hidden
---
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<n>_EL1 and DBGBVR<n>_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;
--
1.9.1
- [Qemu-devel] [PULL 06/19] hw/display/pxa2xx_lcd.c: Remove unused function pxa2xx_dma_rdst_set, (continued)
- [Qemu-devel] [PULL 06/19] hw/display/pxa2xx_lcd.c: Remove unused function pxa2xx_dma_rdst_set, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 04/19] hw/display/blizzard.c: Delete unused function blizzard_rgb2yuv, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 19/19] target-arm: Add support for VIRQ and VFIQ, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 03/19] configure: Build GDB XML for 32 bit ARM CPUs into qemu aarch64 binaries, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 05/19] hw/intc/imx_avic.c: Remove unused function imx_avic_set_prio(), Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 16/19] target-arm: Add a Hypervisor Trap exception type, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 08/19] target-arm: Don't handle c15_cpar changes via tb_flush(), Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 14/19] target-arm: A64: Correct updates to FAR and ESR on exceptions, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 13/19] target-arm: Don't take interrupts targeting lower ELs, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 10/19] target-arm: Add SCR_EL3, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 01/19] target-arm: Implement setting guest breakpoints,
Peter Maydell <=
- [Qemu-devel] [PULL 11/19] target-arm: A64: Refactor aarch64_cpu_do_interrupt, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 09/19] target-arm: Add HCR_EL2, Peter Maydell, 2014/09/29
- [Qemu-devel] [PULL 02/19] target-arm: Implement handling of breakpoint firing, Peter Maydell, 2014/09/29
- Re: [Qemu-devel] [PULL 00/19] target-arm queue, Peter Maydell, 2014/09/30