master
c 86 lines 2.94 KB
Raw
1 /*
2 * QEMU S/390 debug routines
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "qemu/osdep.h"
8 #include "exec/breakpoint.h"
9 #include "exec/watchpoint.h"
10 #include "accel/tcg/cpu-loop.h"
11 #include "target/s390x/cpu.h"
12 #include "target/s390x/s390x-internal.h"
13 #include "tcg_s390x.h"
14
15 void s390_cpu_recompute_watchpoints(CPUState *cs)
16 {
17 const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS;
18 CPUS390XState *env = cpu_env(cs);
19
20 /* We are called when the watchpoints have changed. First
21 remove them all. */
22 cpu_watchpoint_remove_all(cs, BP_CPU);
23
24 /* Return if PER is not enabled */
25 if (!(env->psw.mask & PSW_MASK_PER)) {
26 return;
27 }
28
29 /* Return if storage-alteration event is not enabled. */
30 if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
31 return;
32 }
33
34 if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
35 /* We can't create a watchoint spanning the whole memory range, so
36 split it in two parts. */
37 cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL);
38 cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL);
39 } else if (env->cregs[10] > env->cregs[11]) {
40 /* The address range loops, create two watchpoints. */
41 cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10],
42 wp_flags, NULL);
43 cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL);
44
45 } else {
46 /* Default case, create a single watchpoint. */
47 cpu_watchpoint_insert(cs, env->cregs[10],
48 env->cregs[11] - env->cregs[10] + 1,
49 wp_flags, NULL);
50 }
51 }
52
53 void s390x_cpu_debug_excp_handler(CPUState *cs)
54 {
55 CPUS390XState *env = cpu_env(cs);
56 CPUWatchpoint *wp_hit = cs->watchpoint_hit;
57
58 if (wp_hit && wp_hit->flags & BP_CPU) {
59 /*
60 * FIXME: When the storage-alteration-space control bit is set,
61 * the exception should only be triggered if the memory access
62 * is done using an address space with the storage-alteration-event
63 * bit set. We have no way to detect that with the current
64 * watchpoint code.
65 */
66 cs->watchpoint_hit = NULL;
67
68 env->per_address = env->psw.addr;
69 env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
70 /*
71 * FIXME: We currently no way to detect the address space used
72 * to trigger the watchpoint. For now just consider it is the
73 * current default ASC. This turn to be true except when MVCP
74 * and MVCS instructions are not used.
75 */
76 env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
77
78 /*
79 * Remove all watchpoints to re-execute the code. A PER exception
80 * will be triggered, it will call s390_cpu_set_psw which will
81 * recompute the watchpoints.
82 */
83 cpu_watchpoint_remove_all(cs, BP_CPU);
84 cpu_loop_exit_noexc(cs);
85 }
86 }