aboutsummaryrefslogtreecommitdiff
path: root/target-microblaze/translate.c
diff options
context:
space:
mode:
authorEdgar E. Iglesias <edgar.iglesias@gmail.com>2009-09-03 11:12:30 +0200
committerEdgar E. Iglesias <edgar.iglesias@gmail.com>2009-09-03 11:12:30 +0200
commit1567a0056889b7a2660114d4d50400614fbf0d9e (patch)
treef92ec76192f77b12ba04ad9dfd711e6c828497f7 /target-microblaze/translate.c
parentcedb936bfcc9b7fe9f7df58aa24ca191cba414fe (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/translate.c')
-rw-r--r--target-microblaze/translate.c111
1 files changed, 110 insertions, 1 deletions
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;