On Thu, Sep 1, 2011 at 8:45 PM, Max Filippov <jcmvb...@gmail.com> wrote: > - mark privileged opcodes with ring check; > - make debug exception on exception handler entry. > > Signed-off-by: Max Filippov <jcmvb...@gmail.com> > --- > cpu-exec.c | 6 +++ > target-xtensa/cpu.h | 67 ++++++++++++++++++++++++++++ > target-xtensa/helper.c | 37 +++++++++++++++- > target-xtensa/helpers.h | 2 + > target-xtensa/op_helper.c | 29 ++++++++++++ > target-xtensa/translate.c | 107 ++++++++++++++++++++++++++++++++++++++++++-- > 6 files changed, 242 insertions(+), 6 deletions(-) > > diff --git a/cpu-exec.c b/cpu-exec.c > index 3fce033..2fc37d8 100644 > --- a/cpu-exec.c > +++ b/cpu-exec.c > @@ -488,6 +488,12 @@ int cpu_exec(CPUState *env) > do_interrupt(env); > next_tb = 0; > } > +#elif defined(TARGET_XTENSA) > + if (interrupt_request & CPU_INTERRUPT_HARD) { > + env->exception_index = EXC_IRQ; > + do_interrupt(env); > + next_tb = 0; > + } > #endif > /* Don't use the cached interrupt_request value, > do_interrupt may have updated the EXITTB flag. */ > diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h > index 939222c..cae6637 100644 > --- a/target-xtensa/cpu.h > +++ b/target-xtensa/cpu.h > @@ -108,7 +108,12 @@ enum { > enum { > SAR = 3, > SCOMPARE1 = 12, > + EPC1 = 177, > + DEPC = 192, > + EXCSAVE1 = 209, > PS = 230, > + EXCCAUSE = 232, > + EXCVADDR = 238, > }; > > #define PS_INTLEVEL 0xf > @@ -129,9 +134,60 @@ enum { > > #define PS_WOE 0x40000 > > +enum { > + /* Static vectors */ > + EXC_RESET, > + EXC_MEMORY_ERROR, > + > + /* Dynamic vectors */ > + EXC_WINDOW_OVERFLOW4, > + EXC_WINDOW_UNDERFLOW4, > + EXC_WINDOW_OVERFLOW8, > + EXC_WINDOW_UNDERFLOW8, > + EXC_WINDOW_OVERFLOW12, > + EXC_WINDOW_UNDERFLOW12, > + EXC_IRQ, > + EXC_KERNEL, > + EXC_USER, > + EXC_DOUBLE, > + EXC_MAX > +}; > + > +enum { > + ILLEGAL_INSTRUCTION_CAUSE = 0, > + SYSCALL_CAUSE, > + INSTRUCTION_FETCH_ERROR_CAUSE, > + LOAD_STORE_ERROR_CAUSE, > + LEVEL1_INTERRUPT_CAUSE, > + ALLOCA_CAUSE, > + INTEGER_DIVIDE_BY_ZERO_CAUSE, > + PRIVILEGED_CAUSE = 8, > + LOAD_STORE_ALIGNMENT_CAUSE, > + > + INSTR_PIF_DATA_ERROR_CAUSE = 12, > + LOAD_STORE_PIF_DATA_ERROR_CAUSE, > + INSTR_PIF_ADDR_ERROR_CAUSE, > + LOAD_STORE_PIF_ADDR_ERROR_CAUSE, > + > + INST_TLB_MISS_CAUSE, > + INST_TLB_MULTI_HIT_CAUSE, > + INST_FETCH_PRIVILEGE_CAUSE, > + INST_FETCH_PROHIBITED_CAUSE = 20, > + LOAD_STORE_TLB_MISS_CAUSE = 24, > + LOAD_STORE_TLB_MULTI_HIT_CAUSE, > + LOAD_STORE_PRIVILEGE_CAUSE, > + LOAD_PROHIBITED_CAUSE = 28, > + STORE_PROHIBITED_CAUSE, > + > + COPROCESSOR0_DISABLED = 32, > +}; > + > typedef struct XtensaConfig { > const char *name; > uint64_t options; > + int excm_level; > + int ndepc; > + uint32_t exception_vector[EXC_MAX]; > } XtensaConfig; > > typedef struct CPUXtensaState { > @@ -141,6 +197,8 @@ typedef struct CPUXtensaState { > uint32_t sregs[256]; > uint32_t uregs[256]; > > + int exception_taken; > + > CPU_COMMON > } CPUXtensaState; > > @@ -164,6 +222,15 @@ static inline bool xtensa_option_enabled(const > XtensaConfig *config, int opt) > return (config->options & XTENSA_OPTION_BIT(opt)) != 0; > } > > +static inline int xtensa_get_cintlevel(const CPUState *env) > +{ > + int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT; > + if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) { > + level = env->config->excm_level; > + } > + return level; > +} > + > static inline int xtensa_get_ring(const CPUState *env) > { > if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { > diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c > index 83b8a04..44ebb9f 100644 > --- a/target-xtensa/helper.c > +++ b/target-xtensa/helper.c > @@ -36,7 +36,8 @@ > > void cpu_reset(CPUXtensaState *env) > { > - env->pc = 0; > + env->exception_taken = 0; > + env->pc = env->config->exception_vector[EXC_RESET]; > env->sregs[PS] = 0x1f; > } > > @@ -44,6 +45,20 @@ static const XtensaConfig core_config[] = { > { > .name = "sample-xtensa-core", > .options = -1, > + .ndepc = 1, > + .excm_level = 16, > + .exception_vector = { > + [EXC_RESET] = 0x5fff8000, > + [EXC_WINDOW_OVERFLOW4] = 0x5fff8400, > + [EXC_WINDOW_UNDERFLOW4] = 0x5fff8440, > + [EXC_WINDOW_OVERFLOW8] = 0x5fff8480, > + [EXC_WINDOW_UNDERFLOW8] = 0x5fff84c0, > + [EXC_WINDOW_OVERFLOW12] = 0x5fff8500, > + [EXC_WINDOW_UNDERFLOW12] = 0x5fff8540, > + [EXC_KERNEL] = 0x5fff861c, > + [EXC_USER] = 0x5fff863c, > + [EXC_DOUBLE] = 0x5fff865c, > + }, > }, > }; > > @@ -94,4 +109,24 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, > target_ulong addr) > > void do_interrupt(CPUState *env) > { > + switch (env->exception_index) { > + case EXC_WINDOW_OVERFLOW4: > + case EXC_WINDOW_UNDERFLOW4: > + case EXC_WINDOW_OVERFLOW8: > + case EXC_WINDOW_UNDERFLOW8: > + case EXC_WINDOW_OVERFLOW12: > + case EXC_WINDOW_UNDERFLOW12: > + case EXC_KERNEL: > + case EXC_USER: > + case EXC_DOUBLE: > + if (env->config->exception_vector[env->exception_index]) { > + env->pc = env->config->exception_vector[env->exception_index]; > + env->exception_taken = 1; > + } else { > + qemu_log("%s(pc = %08x) bad exception_index: %d\n", > + __func__, env->pc, env->exception_index); > + } > + break; > + > + } > } > diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h > index 976c8d8..6329c43 100644 > --- a/target-xtensa/helpers.h > +++ b/target-xtensa/helpers.h > @@ -1,6 +1,8 @@ > #include "def-helper.h" > > DEF_HELPER_1(exception, void, i32) > +DEF_HELPER_2(exception_cause, void, i32, i32) > +DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32) > DEF_HELPER_1(nsa, i32, i32) > DEF_HELPER_1(nsau, i32, i32) > > diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c > index c1cfd2e..794a834 100644 > --- a/target-xtensa/op_helper.c > +++ b/target-xtensa/op_helper.c > @@ -59,6 +59,35 @@ void HELPER(exception)(uint32_t excp) > cpu_loop_exit(env); > } > > +void HELPER(exception_cause)(uint32_t pc, uint32_t cause) > +{ > + uint32_t vector; > + > + env->pc = pc; > + if (env->sregs[PS] & PS_EXCM) { > + if (env->config->ndepc) { > + env->sregs[DEPC] = pc; > + } else { > + env->sregs[EPC1] = pc; > + } > + vector = EXC_DOUBLE; > + } else { > + env->sregs[EPC1] = pc; > + vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; > + } > + > + env->sregs[EXCCAUSE] = cause; > + env->sregs[PS] |= PS_EXCM; > + > + HELPER(exception)(vector); > +} > + > +void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t > vaddr) > +{ > + env->sregs[EXCVADDR] = vaddr; > + HELPER(exception_cause)(pc, cause); > +} > + > uint32_t HELPER(nsa)(uint32_t v) > { > if (v & 0x80000000) { > diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c > index b6d0210..4c9db9e 100644 > --- a/target-xtensa/translate.c > +++ b/target-xtensa/translate.c > @@ -67,7 +67,12 @@ static TCGv_i32 cpu_UR[256]; > static const char * const sregnames[256] = { > [SAR] = "SAR", > [SCOMPARE1] = "SCOMPARE1", > + [EPC1] = "EPC1", > + [DEPC] = "DEPC", > + [EXCSAVE1] = "EXCSAVE1", > [PS] = "PS", > + [EXCCAUSE] = "EXCCAUSE", > + [EXCVADDR] = "EXCVADDR", > }; > > static const char * const uregnames[256] = { > @@ -165,6 +170,22 @@ static void gen_exception(int excp) > tcg_temp_free(tmp); > } > > +static void gen_exception_cause(DisasContext *dc, uint32_t cause) > +{ > + TCGv_i32 _pc = tcg_const_i32(dc->pc); > + TCGv_i32 _cause = tcg_const_i32(cause);
Please don't use identifiers starting with underscore. > + gen_helper_exception_cause(_pc, _cause); > + tcg_temp_free(_pc); > + tcg_temp_free(_cause); > +} > + > +static void gen_check_privilege(DisasContext *dc) > +{ > + if (dc->cring) { > + gen_exception_cause(dc, PRIVILEGED_CAUSE); > + } > +} > + > static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot) > { > tcg_gen_mov_i32(cpu_pc, dest); > @@ -392,7 +413,7 @@ static void disas_xtensa_insn(DisasContext *dc) > case 0: /*SNM0*/ > switch (CALLX_M) { > case 0: /*ILL*/ > - TBD(); > + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); > break; > > case 1: /*reserved*/ > @@ -479,7 +500,52 @@ static void disas_xtensa_insn(DisasContext *dc) > break; > > case 3: /*RFEIx*/ > - TBD(); > + switch (RRR_T) { > + case 0: /*RFETx*/ > + HAS_OPTION(XTENSA_OPTION_EXCEPTION); > + switch (RRR_S) { > + case 0: /*RFEx*/ > + gen_check_privilege(dc); > + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], > ~PS_EXCM); > + gen_jump(dc, cpu_SR[EPC1]); > + break; > + > + case 1: /*RFUEx*/ > + RESERVED(); > + break; > + > + case 2: /*RFDEx*/ > + gen_check_privilege(dc); > + gen_jump(dc, cpu_SR[ > + dc->config->ndepc ? DEPC : EPC1]); > + break; > + > + case 4: /*RFWOw*/ > + case 5: /*RFWUw*/ > + HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); > + TBD(); > + break; > + > + default: /*reserved*/ > + RESERVED(); > + break; > + } > + break; > + > + case 1: /*RFIx*/ > + HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT); > + TBD(); > + break; > + > + case 2: /*RFME*/ > + TBD(); > + break; > + > + default: /*reserved*/ > + RESERVED(); > + break; > + > + } > break; > > case 4: /*BREAKx*/ > @@ -489,12 +555,28 @@ static void disas_xtensa_insn(DisasContext *dc) > > case 5: /*SYSCALLx*/ > HAS_OPTION(XTENSA_OPTION_EXCEPTION); > - TBD(); > + switch (RRR_S) { > + case 0: /*SYSCALLx*/ > + gen_exception_cause(dc, SYSCALL_CAUSE); > + break; > + > + case 1: /*SIMCALL*/ > + TBD(); > + break; > + > + default: > + RESERVED(); > + break; > + } > break; > > case 6: /*RSILx*/ > HAS_OPTION(XTENSA_OPTION_INTERRUPT); > - TBD(); > + gen_check_privilege(dc); > + tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]); > + tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); > + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], > + RRR_S | ~PS_INTLEVEL); > break; > > case 7: /*WAITIx*/ > @@ -691,6 +773,9 @@ static void disas_xtensa_insn(DisasContext *dc) > case 6: /*XSR*/ > { > TCGv_i32 tmp = tcg_temp_new_i32(); > + if (RSR_SR >= 64) { > + gen_check_privilege(dc); > + } > tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); > gen_rsr(dc, cpu_R[RRR_T], RSR_SR); > gen_wsr(dc, RSR_SR, tmp); > @@ -799,6 +884,9 @@ static void disas_xtensa_insn(DisasContext *dc) > case 3: /*RST3*/ > switch (OP2) { > case 0: /*RSR*/ > + if (RSR_SR >= 64) { > + gen_check_privilege(dc); > + } > gen_rsr(dc, cpu_R[RRR_T], RSR_SR); > if (!sregnames[RSR_SR]) { > TBD(); > @@ -806,6 +894,9 @@ static void disas_xtensa_insn(DisasContext *dc) > break; > > case 1: /*WSR*/ > + if (RSR_SR >= 64) { > + gen_check_privilege(dc); > + } > gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); > if (!sregnames[RSR_SR]) { > TBD(); > @@ -1421,7 +1512,7 @@ static void disas_xtensa_insn(DisasContext *dc) > break; > > case 6: /*ILL.Nn*/ > - TBD(); > + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); > break; > > default: /*reserved*/ > @@ -1493,6 +1584,12 @@ static void gen_intermediate_code_internal( > > gen_icount_start(); > > + if (env->singlestep_enabled && env->exception_taken) { > + env->exception_taken = 0; > + tcg_gen_movi_i32(cpu_pc, dc.pc); > + gen_exception(EXCP_DEBUG); > + } > + > do { > check_breakpoint(env, &dc); > > -- > 1.7.6 > > >