aboutsummaryrefslogtreecommitdiff
path: root/accel/tcg
diff options
context:
space:
mode:
authorPhilippe Mathieu-Daudé <philmd@linaro.org>2024-01-09 22:53:26 +0100
committerPhilippe Mathieu-Daudé <philmd@linaro.org>2024-01-19 12:28:59 +0100
commit1c3d42c4c9477600720aa1b6825a5d9f5aa43cbe (patch)
treebbd7dc731a7aeadc8715ce1797a015ab0fff428b /accel/tcg
parent16ad9788b5368fb4aded10d1f050316ea6df9989 (diff)
downloadqemu-1c3d42c4c9477600720aa1b6825a5d9f5aa43cbe.zip
qemu-1c3d42c4c9477600720aa1b6825a5d9f5aa43cbe.tar.gz
qemu-1c3d42c4c9477600720aa1b6825a5d9f5aa43cbe.tar.bz2
system/watchpoint: Move TCG specific code to accel/tcg/
Keep system/watchpoint.c accelerator-agnostic by moving TCG specific code to accel/tcg/watchpoint.c. Update meson. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20240111162032.43378-1-philmd@linaro.org>
Diffstat (limited to 'accel/tcg')
-rw-r--r--accel/tcg/meson.build1
-rw-r--r--accel/tcg/watchpoint.c143
2 files changed, 144 insertions, 0 deletions
diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build
index d25638d..c15ac9a 100644
--- a/accel/tcg/meson.build
+++ b/accel/tcg/meson.build
@@ -24,6 +24,7 @@ specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files(
'cputlb.c',
+ 'watchpoint.c',
))
system_ss.add(when: ['CONFIG_TCG'], if_true: files(
diff --git a/accel/tcg/watchpoint.c b/accel/tcg/watchpoint.c
new file mode 100644
index 0000000..d3aab11
--- /dev/null
+++ b/accel/tcg/watchpoint.c
@@ -0,0 +1,143 @@
+/*
+ * CPU watchpoints
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
+#include "exec/exec-all.h"
+#include "exec/translate-all.h"
+#include "sysemu/tcg.h"
+#include "sysemu/replay.h"
+#include "hw/core/tcg-cpu-ops.h"
+#include "hw/core/cpu.h"
+
+/*
+ * Return true if this watchpoint address matches the specified
+ * access (ie the address range covered by the watchpoint overlaps
+ * partially or completely with the address range covered by the
+ * access).
+ */
+static inline bool watchpoint_address_matches(CPUWatchpoint *wp,
+ vaddr addr, vaddr len)
+{
+ /*
+ * We know the lengths are non-zero, but a little caution is
+ * required to avoid errors in the case where the range ends
+ * exactly at the top of the address space and so addr + len
+ * wraps round to zero.
+ */
+ vaddr wpend = wp->vaddr + wp->len - 1;
+ vaddr addrend = addr + len - 1;
+
+ return !(addr > wpend || wp->vaddr > addrend);
+}
+
+/* Return flags for watchpoints that match addr + prot. */
+int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len)
+{
+ CPUWatchpoint *wp;
+ int ret = 0;
+
+ QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+ if (watchpoint_address_matches(wp, addr, len)) {
+ ret |= wp->flags;
+ }
+ }
+ return ret;
+}
+
+/* Generate a debug exception if a watchpoint has been hit. */
+void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
+ MemTxAttrs attrs, int flags, uintptr_t ra)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ CPUWatchpoint *wp;
+
+ assert(tcg_enabled());
+ if (cpu->watchpoint_hit) {
+ /*
+ * We re-entered the check after replacing the TB.
+ * Now raise the debug interrupt so that it will
+ * trigger after the current instruction.
+ */
+ bql_lock();
+ cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
+ bql_unlock();
+ return;
+ }
+
+ if (cc->tcg_ops->adjust_watchpoint_address) {
+ /* this is currently used only by ARM BE32 */
+ addr = cc->tcg_ops->adjust_watchpoint_address(cpu, addr, len);
+ }
+
+ assert((flags & ~BP_MEM_ACCESS) == 0);
+ QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+ int hit_flags = wp->flags & flags;
+
+ if (hit_flags && watchpoint_address_matches(wp, addr, len)) {
+ if (replay_running_debug()) {
+ /*
+ * replay_breakpoint reads icount.
+ * Force recompile to succeed, because icount may
+ * be read only at the end of the block.
+ */
+ if (!cpu->neg.can_do_io) {
+ /* Force execution of one insn next time. */
+ cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
+ cpu_loop_exit_restore(cpu, ra);
+ }
+ /*
+ * Don't process the watchpoints when we are
+ * in a reverse debugging operation.
+ */
+ replay_breakpoint();
+ return;
+ }
+
+ wp->flags |= hit_flags << BP_HIT_SHIFT;
+ wp->hitaddr = MAX(addr, wp->vaddr);
+ wp->hitattrs = attrs;
+
+ if (wp->flags & BP_CPU
+ && cc->tcg_ops->debug_check_watchpoint
+ && !cc->tcg_ops->debug_check_watchpoint(cpu, wp)) {
+ wp->flags &= ~BP_WATCHPOINT_HIT;
+ continue;
+ }
+ cpu->watchpoint_hit = wp;
+
+ mmap_lock();
+ /* This call also restores vCPU state */
+ tb_check_watchpoint(cpu, ra);
+ if (wp->flags & BP_STOP_BEFORE_ACCESS) {
+ cpu->exception_index = EXCP_DEBUG;
+ mmap_unlock();
+ cpu_loop_exit(cpu);
+ } else {
+ /* Force execution of one insn next time. */
+ cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
+ mmap_unlock();
+ cpu_loop_exit_noexc(cpu);
+ }
+ } else {
+ wp->flags &= ~BP_WATCHPOINT_HIT;
+ }
+ }
+}