On Wed, Sep 14, 2011 at 8:43 AM, Alexander Graf <ag...@suse.de> wrote: > From: David Gibson <da...@gibson.dropbear.id.au> > > This patch implements support for the CFAR SPR on POWER7 (Come From > Address Register), which snapshots the PC value at the time of a branch or > an rfid. The latest powerpc-next kernel also catches it and can show it in > xmon or in the signal frames. > > This works well enough to let recent kernels boot (which otherwise oops > on the CFAR access). It hasn't been tested enough to be confident that the > CFAR values are actually accurate, but one thing at a time.
This looks accurate at least for the cases covered. A higher performance implementation could be to only update the register lazily when the SPR is read, in most other times CFAR would be only stored to DisasContext. > Signed-off-by: Ben Herrenschmidt <b...@kernel.crashing.org> > Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> > Signed-off-by: Alexander Graf <ag...@suse.de> > --- > target-ppc/cpu.h | 8 ++++++++ > target-ppc/translate.c | 28 ++++++++++++++++++++++++++++ > target-ppc/translate_init.c | 23 ++++++++++++++++++++++- > 3 files changed, 58 insertions(+), 1 deletions(-) > > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h > index 32706df..3f4af22 100644 > --- a/target-ppc/cpu.h > +++ b/target-ppc/cpu.h > @@ -555,6 +555,8 @@ enum { > /* Decrementer clock: RTC clock (POWER, 601) or bus clock > */ > POWERPC_FLAG_RTC_CLK = 0x00010000, > POWERPC_FLAG_BUS_CLK = 0x00020000, > + /* Has CFAR > */ > + POWERPC_FLAG_CFAR = 0x00040000, > }; > > /*****************************************************************************/ > @@ -872,6 +874,10 @@ struct CPUPPCState { > target_ulong ctr; > /* condition register */ > uint32_t crf[8]; > +#if defined(TARGET_PPC64) > + /* CFAR */ > + target_ulong cfar; > +#endif > /* XER */ > target_ulong xer; > /* Reservation address */ > @@ -1204,6 +1210,7 @@ static inline void cpu_clone_regs(CPUState *env, > target_ulong newsp) > #define SPR_601_UDECR (0x006) > #define SPR_LR (0x008) > #define SPR_CTR (0x009) > +#define SPR_DSCR (0x011) > #define SPR_DSISR (0x012) > #define SPR_DAR (0x013) /* DAE for PowerPC 601 */ > #define SPR_601_RTCU (0x014) > @@ -1212,6 +1219,7 @@ static inline void cpu_clone_regs(CPUState *env, > target_ulong newsp) > #define SPR_SDR1 (0x019) > #define SPR_SRR0 (0x01A) > #define SPR_SRR1 (0x01B) > +#define SPR_CFAR (0x01C) > #define SPR_AMR (0x01D) > #define SPR_BOOKE_PID (0x030) > #define SPR_BOOKE_DECAR (0x036) > diff --git a/target-ppc/translate.c b/target-ppc/translate.c > index 4277460..1e362fc 100644 > --- a/target-ppc/translate.c > +++ b/target-ppc/translate.c > @@ -69,6 +69,9 @@ static TCGv cpu_nip; > static TCGv cpu_msr; > static TCGv cpu_ctr; > static TCGv cpu_lr; > +#if defined(TARGET_PPC64) > +static TCGv cpu_cfar; > +#endif > static TCGv cpu_xer; > static TCGv cpu_reserve; > static TCGv_i32 cpu_fpscr; > @@ -154,6 +157,11 @@ void ppc_translate_init(void) > cpu_lr = tcg_global_mem_new(TCG_AREG0, > offsetof(CPUState, lr), "lr"); > > +#if defined(TARGET_PPC64) > + cpu_cfar = tcg_global_mem_new(TCG_AREG0, > + offsetof(CPUState, cfar), "cfar"); > +#endif > + > cpu_xer = tcg_global_mem_new(TCG_AREG0, > offsetof(CPUState, xer), "xer"); > > @@ -187,6 +195,7 @@ typedef struct DisasContext { > int le_mode; > #if defined(TARGET_PPC64) > int sf_mode; > + int has_cfar; > #endif > int fpu_enabled; > int altivec_enabled; > @@ -3345,6 +3354,14 @@ static inline void gen_qemu_st32fiw(DisasContext *ctx, > TCGv_i64 arg1, TCGv arg2) > /* stfiwx */ > GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX); > > +static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip) > +{ > +#if defined(TARGET_PPC64) > + if (ctx->has_cfar) Braces missing, please use checkpatch.pl. > + tcg_gen_movi_tl(cpu_cfar, nip); > +#endif > +} > + > /*** Branch > ***/ > static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) > { > @@ -3407,6 +3424,7 @@ static void gen_b(DisasContext *ctx) > target = li; > if (LK(ctx->opcode)) > gen_setlr(ctx, ctx->nip); > + gen_update_cfar(ctx, ctx->nip); > gen_goto_tb(ctx, 0, target); > } > > @@ -3469,6 +3487,7 @@ static inline void gen_bcond(DisasContext *ctx, int > type) > } > tcg_temp_free_i32(temp); > } > + gen_update_cfar(ctx, ctx->nip); > if (type == BCOND_IM) { > target_ulong li = (target_long)((int16_t)(BD(ctx->opcode))); > if (likely(AA(ctx->opcode) == 0)) { > @@ -3580,6 +3599,7 @@ static void gen_rfi(DisasContext *ctx) > gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); > return; > } > + gen_update_cfar(ctx, ctx->nip); > gen_helper_rfi(); > gen_sync_exception(ctx); > #endif > @@ -3596,6 +3616,7 @@ static void gen_rfid(DisasContext *ctx) > gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); > return; > } > + gen_update_cfar(ctx, ctx->nip); > gen_helper_rfid(); > gen_sync_exception(ctx); > #endif > @@ -9263,6 +9284,12 @@ void cpu_dump_state (CPUState *env, FILE *f, > fprintf_function cpu_fprintf, > */ > } > > +#if defined(TARGET_PPC64) > + if (env->flags & POWERPC_FLAG_CFAR) { > + cpu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar); > + } > +#endif > + > switch (env->mmu_model) { > case POWERPC_MMU_32B: > case POWERPC_MMU_601: > @@ -9371,6 +9398,7 @@ static inline void > gen_intermediate_code_internal(CPUState *env, > ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0; > #if defined(TARGET_PPC64) > ctx.sf_mode = msr_sf; > + ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR); > #endif > ctx.fpu_enabled = msr_fp; > if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c > index 9ea193d..211f3bd 100644 > --- a/target-ppc/translate_init.c > +++ b/target-ppc/translate_init.c > @@ -129,6 +129,19 @@ static void spr_write_lr (void *opaque, int sprn, int > gprn) > tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]); > } > > +/* CFAR */ > +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) > +static void spr_read_cfar (void *opaque, int gprn, int sprn) > +{ > + tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar); > +} > + > +static void spr_write_cfar (void *opaque, int sprn, int gprn) > +{ > + tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]); > +} > +#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */ > + > /* CTR */ > static void spr_read_ctr (void *opaque, int gprn, int sprn) > { > @@ -6489,7 +6502,7 @@ static void init_proc_970MP (CPUPPCState *env) > #define POWERPC_BFDM_POWER7 (bfd_mach_ppc64) > #define POWERPC_FLAG_POWER7 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | > \ > POWERPC_FLAG_BE | POWERPC_FLAG_PMM | > \ > - POWERPC_FLAG_BUS_CLK) > + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR) > #define check_pow_POWER7 check_pow_nocheck > > static void init_proc_POWER7 (CPUPPCState *env) > @@ -6508,6 +6521,14 @@ static void init_proc_POWER7 (CPUPPCState *env) > &spr_read_purr, SPR_NOACCESS, > &spr_read_purr, SPR_NOACCESS, > 0x00000000); > + spr_register(env, SPR_CFAR, "SPR_CFAR", > + SPR_NOACCESS, SPR_NOACCESS, > + &spr_read_cfar, &spr_write_cfar, > + 0x00000000); > + spr_register(env, SPR_DSCR, "SPR_DSCR", > + SPR_NOACCESS, SPR_NOACCESS, > + &spr_read_generic, &spr_write_generic, > + 0x00000000); > #endif /* !CONFIG_USER_ONLY */ > /* Memory management */ > /* XXX : not implemented */ > -- > 1.6.0.2 > >