aboutsummaryrefslogtreecommitdiffstats
path: root/target-microblaze
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
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')
-rw-r--r--target-microblaze/microblaze-decode.h1
-rw-r--r--target-microblaze/translate.c111
2 files changed, 111 insertions, 1 deletions
diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h
index 2c975d667..602027dbf 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 9c8631dc2..16b282f57 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;