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>
diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h
index 2c975d6..602027d 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 9c8631d..16b282f 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -231,6 +231,13 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 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 @@
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 @@
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 @@
{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 @@
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 void check_breakpoint(CPUState *env, DisasContext *dc)
{
CPUBreakpoint *bp;