blob: 50d2853d443844b84a01184787b8f840a8668fe6 [file] [log] [blame]
/*
* QEMU S/390 debug routines
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "exec/breakpoint.h"
#include "exec/watchpoint.h"
#include "target/s390x/cpu.h"
#include "target/s390x/s390x-internal.h"
#include "tcg_s390x.h"
void s390_cpu_recompute_watchpoints(CPUState *cs)
{
const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS;
CPUS390XState *env = cpu_env(cs);
/* We are called when the watchpoints have changed. First
remove them all. */
cpu_watchpoint_remove_all(cs, BP_CPU);
/* Return if PER is not enabled */
if (!(env->psw.mask & PSW_MASK_PER)) {
return;
}
/* Return if storage-alteration event is not enabled. */
if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
return;
}
if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
/* We can't create a watchoint spanning the whole memory range, so
split it in two parts. */
cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL);
cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL);
} else if (env->cregs[10] > env->cregs[11]) {
/* The address range loops, create two watchpoints. */
cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10],
wp_flags, NULL);
cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL);
} else {
/* Default case, create a single watchpoint. */
cpu_watchpoint_insert(cs, env->cregs[10],
env->cregs[11] - env->cregs[10] + 1,
wp_flags, NULL);
}
}
void s390x_cpu_debug_excp_handler(CPUState *cs)
{
CPUS390XState *env = cpu_env(cs);
CPUWatchpoint *wp_hit = cs->watchpoint_hit;
if (wp_hit && wp_hit->flags & BP_CPU) {
/*
* FIXME: When the storage-alteration-space control bit is set,
* the exception should only be triggered if the memory access
* is done using an address space with the storage-alteration-event
* bit set. We have no way to detect that with the current
* watchpoint code.
*/
cs->watchpoint_hit = NULL;
env->per_address = env->psw.addr;
env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
/*
* FIXME: We currently no way to detect the address space used
* to trigger the watchpoint. For now just consider it is the
* current default ASC. This turn to be true except when MVCP
* and MVCS instructions are not used.
*/
env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
/*
* Remove all watchpoints to re-execute the code. A PER exception
* will be triggered, it will call s390_cpu_set_psw which will
* recompute the watchpoints.
*/
cpu_watchpoint_remove_all(cs, BP_CPU);
cpu_loop_exit_noexc(cs);
}
}