diff options
author | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2009-09-03 11:12:30 +0200 |
---|---|---|
committer | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2009-09-03 11:12:30 +0200 |
commit | 1567a0056889b7a2660114d4d50400614fbf0d9e (patch) | |
tree | f92ec76192f77b12ba04ad9dfd711e6c828497f7 /target-microblaze | |
parent | cedb936bfcc9b7fe9f7df58aa24ca191cba414fe (diff) |
microblaze: Catch illegal insns and privilege violations.
Raise illegal instruction exceptions when executing instructions that
require units not available on the particulare microblaze configuration.
Also trap priviliege violations made by userspace.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Diffstat (limited to 'target-microblaze')
-rw-r--r-- | target-microblaze/microblaze-decode.h | 1 | ||||
-rw-r--r-- | target-microblaze/translate.c | 111 |
2 files changed, 111 insertions, 1 deletions
diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h index 2c975d6677..602027dbfb 100644 --- a/target-microblaze/microblaze-decode.h +++ b/target-microblaze/microblaze-decode.h @@ -41,6 +41,7 @@ #define DEC_BARREL {B8(00010001), B8(00110111)} #define DEC_MUL {B8(00010000), B8(00110111)} #define DEC_DIV {B8(00010010), B8(00110111)} +#define DEC_FPU {B8(00111111), B8(00010110)} #define DEC_LD {B8(00110000), B8(00110100)} #define DEC_ST {B8(00110100), B8(00110100)} diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 9c8631dc21..16b282f577 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -231,6 +231,13 @@ static void dec_pattern(DisasContext *dc) unsigned int mode; int l1; + if ((dc->tb_flags & MSR_EE_FLAG) + && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK) + && !((dc->env->pvr.regs[2] & PVR2_USE_PCMP_INSTR))) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + } + mode = dc->opcode & 3; switch (mode) { case 0: @@ -358,6 +365,7 @@ static void dec_msr(DisasContext *dc) { TCGv t0, t1; unsigned int sr, to, rn; + int mem_index = cpu_mmu_index(dc->env); sr = dc->imm & ((1 << 14) - 1); to = dc->imm & (1 << 14); @@ -371,6 +379,19 @@ static void dec_msr(DisasContext *dc) LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set", dc->rd, dc->imm); + + if (!(dc->env->pvr.regs[2] & PVR2_USE_MSR_INSTR)) { + /* nop??? */ + return; + } + + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX && (dc->imm != 4 && dc->imm != 0)) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + if (dc->rd) msr_read(dc, cpu_R[dc->rd]); @@ -392,6 +413,15 @@ static void dec_msr(DisasContext *dc) return; } + if (to) { + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + } + #if !defined(CONFIG_USER_ONLY) /* Catch read/writes to the mmu block. */ if ((sr & ~0xff) == 0x1000) { @@ -518,6 +548,14 @@ static void dec_mul(DisasContext *dc) TCGv d[2]; unsigned int subcode; + if ((dc->tb_flags & MSR_EE_FLAG) + && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK) + && !(dc->env->pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + subcode = dc->imm & 3; d[0] = tcg_temp_new(); d[1] = tcg_temp_new(); @@ -528,6 +566,12 @@ static void dec_mul(DisasContext *dc) goto done; } + /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */ + if (subcode >= 1 && subcode <= 3 + && !((dc->env->pvr.regs[2] & PVR2_USE_MUL64_MASK))) { + /* nop??? */ + } + switch (subcode) { case 0: LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); @@ -562,6 +606,12 @@ static void dec_div(DisasContext *dc) u = dc->imm & 2; LOG_DIS("div\n"); + if (!(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK) + && !((dc->env->pvr.regs[0] & PVR0_USE_DIV_MASK))) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + } + /* FIXME: support div by zero exceptions. */ if (u) gen_helper_divu(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); @@ -576,6 +626,14 @@ static void dec_barrel(DisasContext *dc) TCGv t0; unsigned int s, t; + if ((dc->tb_flags & MSR_EE_FLAG) + && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK) + && !(dc->env->pvr.regs[0] & PVR0_USE_BARREL_MASK)) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + s = dc->imm & (1 << 10); t = dc->imm & (1 << 9); @@ -601,6 +659,7 @@ static void dec_bit(DisasContext *dc) { TCGv t0, t1; unsigned int op; + int mem_index = cpu_mmu_index(dc->env); op = dc->ir & ((1 << 8) - 1); switch (op) { @@ -653,10 +712,22 @@ static void dec_bit(DisasContext *dc) case 0x64: /* wdc. */ LOG_DIS("wdc r%d\n", dc->ra); + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } break; case 0x68: /* wic. */ LOG_DIS("wic r%d\n", dc->ra); + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } break; default: cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", @@ -966,6 +1037,7 @@ static inline void do_rte(DisasContext *dc) static void dec_rts(DisasContext *dc) { unsigned int b_bit, i_bit, e_bit; + int mem_index = cpu_mmu_index(dc->env); i_bit = dc->ir & (1 << 21); b_bit = dc->ir & (1 << 22); @@ -978,12 +1050,27 @@ static void dec_rts(DisasContext *dc) if (i_bit) { LOG_DIS("rtid ir=%x\n", dc->ir); + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + } dc->tb_flags |= DRTI_FLAG; } else if (b_bit) { LOG_DIS("rtbd ir=%x\n", dc->ir); + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + } dc->tb_flags |= DRTB_FLAG; } else if (e_bit) { LOG_DIS("rted ir=%x\n", dc->ir); + if ((dc->tb_flags & MSR_EE_FLAG) + && mem_index == MMU_USER_IDX) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + } dc->tb_flags |= DRTE_FLAG; } else LOG_DIS("rts ir=%x\n", dc->ir); @@ -992,6 +1079,20 @@ static void dec_rts(DisasContext *dc) tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc))); } +static void dec_fpu(DisasContext *dc) +{ + if ((dc->tb_flags & MSR_EE_FLAG) + && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK) + && !((dc->env->pvr.regs[2] & PVR2_USE_FPU_MASK))) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + + qemu_log ("unimplemented FPU insn pc=%x opc=%x\n", dc->pc, dc->opcode); + dc->abort_at_next_insn = 1; +} + static void dec_null(DisasContext *dc) { qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode); @@ -1018,6 +1119,7 @@ static struct decoder_info { {DEC_BR, dec_br}, {DEC_BCC, dec_bcc}, {DEC_RTS, dec_rts}, + {DEC_FPU, dec_fpu}, {DEC_MUL, dec_mul}, {DEC_DIV, dec_div}, {DEC_MSR, dec_msr}, @@ -1038,6 +1140,14 @@ static inline void decode(DisasContext *dc) if (dc->ir) dc->nr_nops = 0; else { + if ((dc->tb_flags & MSR_EE_FLAG) + && !(dc->env->pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK) + && !(dc->env->pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) { + tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP); + t_gen_raise_exception(dc, EXCP_HW_EXCP); + return; + } + LOG_DIS("nr_nops=%d\t", dc->nr_nops); dc->nr_nops++; if (dc->nr_nops > 4) @@ -1061,7 +1171,6 @@ static inline void decode(DisasContext *dc) } } - static void check_breakpoint(CPUState *env, DisasContext *dc) { CPUBreakpoint *bp; |