Skip to content

Commit

Permalink
target/ppc: Implement watchpoint debug facility for v2.07S
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
npiggin authored and legoater committed Sep 4, 2023
1 parent 6f772e5 commit 446e514
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 3 deletions.
59 changes: 59 additions & 0 deletions target/ppc/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions target/ppc/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

Expand Down
6 changes: 4 additions & 2 deletions target/ppc/cpu_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 */
Expand Down
52 changes: 51 additions & 1 deletion target/ppc/excp_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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 */
2 changes: 2 additions & 0 deletions target/ppc/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions target/ppc/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions target/ppc/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,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);
}
Expand Down
10 changes: 10 additions & 0 deletions target/ppc/misc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions target/ppc/spr_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions target/ppc/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,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 */
Expand Down

0 comments on commit 446e514

Please sign in to comment.