target/ppc: Implement watchpoint debug facility for v2.07S

ISA v2.07S introduced the watchpoint facility based on the DAWR0
and DAWRX0 SPRs. Implement this in TCG.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
Nicholas Piggin 2023-08-08 13:11:15 +10:00 committed by Cédric Le Goater
parent 14192307ef
commit d5ee641cfc
10 changed files with 147 additions and 3 deletions

View File

@ -128,6 +128,65 @@ void ppc_store_ciabr(CPUPPCState *env, target_ulong val)
env->spr[SPR_CIABR] = val;
ppc_update_ciabr(env);
}
void ppc_update_daw0(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
target_ulong deaw = env->spr[SPR_DAWR0] & PPC_BITMASK(0, 60);
uint32_t dawrx = env->spr[SPR_DAWRX0];
int mrd = extract32(dawrx, PPC_BIT_NR(48), 54 - 48);
bool dw = extract32(dawrx, PPC_BIT_NR(57), 1);
bool dr = extract32(dawrx, PPC_BIT_NR(58), 1);
bool hv = extract32(dawrx, PPC_BIT_NR(61), 1);
bool sv = extract32(dawrx, PPC_BIT_NR(62), 1);
bool pr = extract32(dawrx, PPC_BIT_NR(62), 1);
vaddr len;
int flags;
if (env->dawr0_watchpoint) {
cpu_watchpoint_remove_by_ref(cs, env->dawr0_watchpoint);
env->dawr0_watchpoint = NULL;
}
if (!dr && !dw) {
return;
}
if (!hv && !sv && !pr) {
return;
}
len = (mrd + 1) * 8;
flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
if (dr) {
flags |= BP_MEM_READ;
}
if (dw) {
flags |= BP_MEM_WRITE;
}
cpu_watchpoint_insert(cs, deaw, len, flags, &env->dawr0_watchpoint);
}
void ppc_store_dawr0(CPUPPCState *env, target_ulong val)
{
env->spr[SPR_DAWR0] = val;
ppc_update_daw0(env);
}
void ppc_store_dawrx0(CPUPPCState *env, uint32_t val)
{
int hrammc = extract32(val, PPC_BIT_NR(56), 1);
if (hrammc) {
/* This might be done with a second watchpoint at the xor of DEAW[0] */
qemu_log_mask(LOG_UNIMP, "%s: DAWRX0[HRAMMC] is unimplemented\n",
__func__);
}
env->spr[SPR_DAWRX0] = val;
ppc_update_daw0(env);
}
#endif
#endif

View File

@ -1138,6 +1138,7 @@ struct CPUArchState {
#if defined(TARGET_PPC64)
ppc_slb_t slb[MAX_SLB_ENTRIES]; /* PowerPC 64 SLB area */
struct CPUBreakpoint *ciabr_breakpoint;
struct CPUWatchpoint *dawr0_watchpoint;
#endif
target_ulong sr[32]; /* segment registers */
uint32_t nb_BATs; /* number of BATs */
@ -1406,6 +1407,9 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
void ppc_update_ciabr(CPUPPCState *env);
void ppc_store_ciabr(CPUPPCState *env, target_ulong value);
void ppc_update_daw0(CPUPPCState *env);
void ppc_store_dawr0(CPUPPCState *env, target_ulong value);
void ppc_store_dawrx0(CPUPPCState *env, uint32_t value);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr(CPUPPCState *env, target_ulong value);

View File

@ -5117,12 +5117,12 @@ static void register_book3s_207_dbg_sprs(CPUPPCState *env)
spr_register_kvm_hv(env, SPR_DAWR0, "DAWR0",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
&spr_read_generic, &spr_write_dawr0,
KVM_REG_PPC_DAWR, 0x00000000);
spr_register_kvm_hv(env, SPR_DAWRX0, "DAWRX0",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic32,
&spr_read_generic, &spr_write_dawrx0,
KVM_REG_PPC_DAWRX, 0x00000000);
spr_register_kvm_hv(env, SPR_CIABR, "CIABR",
SPR_NOACCESS, SPR_NOACCESS,
@ -7160,6 +7160,7 @@ static void ppc_cpu_reset_hold(Object *obj)
if (tcg_enabled()) {
cpu_breakpoint_remove_all(s, BP_CPU);
cpu_watchpoint_remove_all(s, BP_CPU);
if (env->mmu_model != POWERPC_MMU_REAL) {
ppc_tlb_invalidate_all(env);
}
@ -7349,6 +7350,7 @@ static const struct TCGCPUOps ppc_tcg_ops = {
.do_transaction_failed = ppc_cpu_do_transaction_failed,
.debug_excp_handler = ppc_cpu_debug_excp_handler,
.debug_check_breakpoint = ppc_cpu_debug_check_breakpoint,
.debug_check_watchpoint = ppc_cpu_debug_check_watchpoint,
#endif /* !CONFIG_USER_ONLY */
};
#endif /* CONFIG_TCG */

View File

@ -3264,7 +3264,15 @@ void ppc_cpu_debug_excp_handler(CPUState *cs)
CPUPPCState *env = cs->env_ptr;
if (env->insns_flags2 & PPC2_ISA207S) {
if (cpu_breakpoint_test(cs, env->nip, BP_CPU)) {
if (cs->watchpoint_hit) {
if (cs->watchpoint_hit->flags & BP_CPU) {
env->spr[SPR_DAR] = cs->watchpoint_hit->hitaddr;
env->spr[SPR_DSISR] = PPC_BIT(41);
cs->watchpoint_hit = NULL;
raise_exception(env, POWERPC_EXCP_DSI);
}
cs->watchpoint_hit = NULL;
} else if (cpu_breakpoint_test(cs, env->nip, BP_CPU)) {
raise_exception_err(env, POWERPC_EXCP_TRACE,
PPC_BIT(33) | PPC_BIT(43));
}
@ -3299,5 +3307,47 @@ bool ppc_cpu_debug_check_breakpoint(CPUState *cs)
return false;
}
bool ppc_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
{
#if defined(TARGET_PPC64)
CPUPPCState *env = cs->env_ptr;
if (env->insns_flags2 & PPC2_ISA207S) {
if (wp == env->dawr0_watchpoint) {
uint32_t dawrx = env->spr[SPR_DAWRX0];
bool wt = extract32(dawrx, PPC_BIT_NR(59), 1);
bool wti = extract32(dawrx, PPC_BIT_NR(60), 1);
bool hv = extract32(dawrx, PPC_BIT_NR(61), 1);
bool sv = extract32(dawrx, PPC_BIT_NR(62), 1);
bool pr = extract32(dawrx, PPC_BIT_NR(62), 1);
if ((env->msr & ((target_ulong)1 << MSR_PR)) && !pr) {
return false;
} else if ((env->msr & ((target_ulong)1 << MSR_HV)) && !hv) {
return false;
} else if (!sv) {
return false;
}
if (!wti) {
if (env->msr & ((target_ulong)1 << MSR_DR)) {
if (!wt) {
return false;
}
} else {
if (wt) {
return false;
}
}
}
return true;
}
}
#endif
return false;
}
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */

View File

@ -26,6 +26,8 @@ DEF_HELPER_2(rfebb, void, env, tl)
DEF_HELPER_2(store_lpcr, void, env, tl)
DEF_HELPER_2(store_pcr, void, env, tl)
DEF_HELPER_2(store_ciabr, void, env, tl)
DEF_HELPER_2(store_dawr0, void, env, tl)
DEF_HELPER_2(store_dawrx0, void, env, tl)
DEF_HELPER_2(store_mmcr0, void, env, tl)
DEF_HELPER_2(store_mmcr1, void, env, tl)
DEF_HELPER_3(store_pmc, void, env, i32, i64)

View File

@ -303,6 +303,7 @@ void ppc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
MemTxResult response, uintptr_t retaddr);
void ppc_cpu_debug_excp_handler(CPUState *cs);
bool ppc_cpu_debug_check_breakpoint(CPUState *cs);
bool ppc_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
#endif
FIELD(GER_MSK, XMSK, 0, 4)

View File

@ -316,6 +316,7 @@ static int cpu_post_load(void *opaque, int version_id)
/* Re-set breaks based on regs */
#if defined(TARGET_PPC64)
ppc_update_ciabr(env);
ppc_update_daw0(env);
#endif
pmu_mmcr01_updated(env);
}

View File

@ -204,6 +204,16 @@ void helper_store_ciabr(CPUPPCState *env, target_ulong value)
ppc_store_ciabr(env, value);
}
void helper_store_dawr0(CPUPPCState *env, target_ulong value)
{
ppc_store_dawr0(env, value);
}
void helper_store_dawrx0(CPUPPCState *env, target_ulong value)
{
ppc_store_dawrx0(env, value);
}
/*
* DPDES register is shared. Each bit reflects the state of the
* doorbell interrupt of a thread of the same core.

View File

@ -160,6 +160,8 @@ void spr_read_mas73(DisasContext *ctx, int gprn, int sprn);
void spr_read_cfar(DisasContext *ctx, int gprn, int sprn);
void spr_write_cfar(DisasContext *ctx, int sprn, int gprn);
void spr_write_ciabr(DisasContext *ctx, int sprn, int gprn);
void spr_write_dawr0(DisasContext *ctx, int sprn, int gprn);
void spr_write_dawrx0(DisasContext *ctx, int sprn, int gprn);
void spr_write_ureg(DisasContext *ctx, int sprn, int gprn);
void spr_read_purr(DisasContext *ctx, int gprn, int sprn);
void spr_write_purr(DisasContext *ctx, int sprn, int gprn);

View File

@ -576,6 +576,19 @@ void spr_write_ciabr(DisasContext *ctx, int sprn, int gprn)
translator_io_start(&ctx->base);
gen_helper_store_ciabr(cpu_env, cpu_gpr[gprn]);
}
/* Watchpoint */
void spr_write_dawr0(DisasContext *ctx, int sprn, int gprn)
{
translator_io_start(&ctx->base);
gen_helper_store_dawr0(cpu_env, cpu_gpr[gprn]);
}
void spr_write_dawrx0(DisasContext *ctx, int sprn, int gprn)
{
translator_io_start(&ctx->base);
gen_helper_store_dawrx0(cpu_env, cpu_gpr[gprn]);
}
#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
/* CTR */