From 24c7b0e330fdbfcfe87f515d79e67156c57cbc4f Mon Sep 17 00:00:00 2001 From: ths Date: Fri, 30 Mar 2007 16:44:54 +0000 Subject: [PATCH] Sanitize mips exception handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2546 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-exec.c | 6 ++--- dyngen-exec.h | 1 + hw/mips_int.c | 15 ++++++------ target-mips/cpu.h | 2 -- target-mips/helper.c | 45 ++++++++++++++++-------------------- target-mips/op.c | 51 ++++++++++++++++++++++------------------- target-mips/op_helper.c | 8 ++++--- target-mips/translate.c | 22 +++--------------- 8 files changed, 66 insertions(+), 84 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index d124c4059..d16888662 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -461,10 +461,10 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && (env->CP0_Status & (1 << CP0St_IE)) && - (env->CP0_Status & env->CP0_Cause & 0x0000FF00) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { /* Raise it */ env->exception_index = EXCP_EXT_INTERRUPT; diff --git a/dyngen-exec.h b/dyngen-exec.h index bf40353b2..c63eb265d 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -80,6 +80,7 @@ typedef void * host_reg_t; typedef struct FILE FILE; extern int fprintf(FILE *, const char *, ...); +extern int fputs(const char *, FILE *); extern int printf(const char *, ...); #undef NULL #define NULL 0 diff --git a/hw/mips_int.c b/hw/mips_int.c index 7f9f15305..b384b64d2 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -5,17 +5,16 @@ IRQ may change */ void cpu_mips_update_irq(CPUState *env) { - if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && - (env->CP0_Status & (1 << CP0St_IE)) && - !(env->hflags & MIPS_HFLAG_EXL) && - !(env->hflags & MIPS_HFLAG_ERL) && - !(env->hflags & MIPS_HFLAG_DM)) { - if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) { + if ((env->CP0_Status & (1 << CP0St_IE)) && + !(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM)) { + if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && + !(env->interrupt_request & CPU_INTERRUPT_HARD)) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } - } else { + } else cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } } void cpu_mips_irq_request(void *opaque, int irq, int level) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index f0f3ab2d7..4fec3cc88 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -248,8 +248,6 @@ struct CPUMIPSState { #define MIPS_HFLAG_TMASK 0x007F #define MIPS_HFLAG_MODE 0x001F /* execution modes */ #define MIPS_HFLAG_UM 0x0001 /* user mode */ -#define MIPS_HFLAG_ERL 0x0002 /* Error mode */ -#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */ #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ diff --git a/target-mips/helper.c b/target-mips/helper.c index 0b23f359f..fe5b2ab67 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -90,7 +90,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, if (user_mode && address > 0x7FFFFFFFUL) return TLBRET_BADADDR; if (address < (int32_t)0x80000000UL) { - if (!(env->hflags & MIPS_HFLAG_ERL)) { + if (!(env->CP0_Status & (1 << CP0St_ERL))) { #ifdef MIPS_USES_R4K_TLB ret = map_address(env, physical, prot, address, rw, access_type); #else @@ -289,21 +289,18 @@ void do_interrupt (CPUState *env) goto set_DEPC; case EXCP_DDBL: env->CP0_Debug |= 1 << CP0DB_DDBL; - goto set_DEPC; set_DEPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_DEPC = env->PC - 4; - if (!(env->hflags & MIPS_HFLAG_EXL)) - env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_DEPC = env->PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM; + env->hflags &= ~MIPS_HFLAG_UM; /* EJTAG probe trap enable is not implemented... */ env->PC = (int32_t)0xBFC00480; break; @@ -311,25 +308,22 @@ void do_interrupt (CPUState *env) cpu_reset(env); break; case EXCP_SRESET: - env->CP0_Status = (1 << CP0St_SR); + env->CP0_Status |= (1 << CP0St_SR); env->CP0_WatchLo = 0; goto set_error_EPC; case EXCP_NMI: - env->CP0_Status = (1 << CP0St_NMI); + env->CP0_Status |= (1 << CP0St_NMI); set_error_EPC: if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ env->CP0_ErrorEPC = env->PC - 4; - if (!(env->hflags & MIPS_HFLAG_EXL)) - env->CP0_Cause |= (1 << CP0Ca_BD); env->hflags &= ~MIPS_HFLAG_BMASK; } else { env->CP0_ErrorEPC = env->PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); } - env->hflags |= MIPS_HFLAG_ERL; - env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); + env->hflags &= ~MIPS_HFLAG_UM; env->PC = (int32_t)0xBFC00000; break; case EXCP_MCHECK: @@ -350,7 +344,7 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBL: cause = 2; - if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) offset = 0x000; goto set_EPC; case EXCP_IBE: @@ -384,28 +378,29 @@ void do_interrupt (CPUState *env) goto set_EPC; case EXCP_TLBS: cause = 3; - if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) offset = 0x000; - goto set_EPC; set_EPC: - if (env->hflags & MIPS_HFLAG_BMASK) { - /* If the exception was raised from a delay slot, - come back to the jump. */ - env->CP0_EPC = env->PC - 4; - if (!(env->hflags & MIPS_HFLAG_EXL)) + if (!(env->CP0_Status & (1 << CP0St_EXL))) { + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, + come back to the jump. */ + env->CP0_EPC = env->PC - 4; env->CP0_Cause |= (1 << CP0Ca_BD); - env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags &= ~MIPS_HFLAG_BMASK; + } else { + env->CP0_EPC = env->PC; + env->CP0_Cause &= ~(1 << CP0Ca_BD); + } } else { - env->CP0_EPC = env->PC; - env->CP0_Cause &= ~(1 << CP0Ca_BD); + env->CP0_Status |= (1 << CP0St_EXL); + env->hflags &= ~MIPS_HFLAG_UM; } if (env->CP0_Status & (1 << CP0St_BEV)) { env->PC = (int32_t)0xBFC00200; } else { env->PC = (int32_t)0x80000000; } - env->hflags |= MIPS_HFLAG_EXL; - env->CP0_Status |= (1 << CP0St_EXL); env->PC += offset; env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); break; diff --git a/target-mips/op.c b/target-mips/op.c index f97ec4292..fecf18cc6 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1105,12 +1105,6 @@ void op_mfc0_compare (void) void op_mfc0_status (void) { T0 = env->CP0_Status; - if (env->hflags & MIPS_HFLAG_UM) - T0 |= (1 << CP0St_UM); - if (env->hflags & MIPS_HFLAG_ERL) - T0 |= (1 << CP0St_ERL); - if (env->hflags & MIPS_HFLAG_EXL) - T0 |= (1 << CP0St_EXL); RETURN(); } @@ -1365,20 +1359,10 @@ void op_mtc0_status (void) { uint32_t val, old; - val = (int32_t)T0 & 0xFA78FF01; + /* No 64bit FPU, no reverse endianness, no MDMX/DSP, no 64bit ops, + no 64bit addressing implemented. */ + val = (int32_t)T0 & 0xF878FF17; old = env->CP0_Status; - if (T0 & (1 << CP0St_UM)) - env->hflags |= MIPS_HFLAG_UM; - else - env->hflags &= ~MIPS_HFLAG_UM; - if (T0 & (1 << CP0St_ERL)) - env->hflags |= MIPS_HFLAG_ERL; - else - env->hflags &= ~MIPS_HFLAG_ERL; - if (T0 & (1 << CP0St_EXL)) - env->hflags |= MIPS_HFLAG_EXL; - else - env->hflags &= ~MIPS_HFLAG_EXL; env->CP0_Status = val; if (loglevel & CPU_LOG_TB_IN_ASM) CALL_FROM_TB2(do_mtc0_status_debug, old, val); @@ -1662,6 +1646,15 @@ void op_dmtc0_errorepc (void) # define DEBUG_FPU_STATE() do { } while(0) #endif +void op_cp0_enabled(void) +{ + if (!(env->CP0_Status & (1 << CP0St_CU0)) && + (env->hflags & MIPS_HFLAG_UM)) { + CALL_FROM_TB2(do_raise_exception_direct_err, EXCP_CpU, 0); + } + RETURN(); +} + void op_cp1_enabled(void) { if (!(env->CP0_Status & (1 << CP0St_CU1))) { @@ -2091,15 +2084,18 @@ void debug_eret (void); void op_eret (void) { CALL_FROM_TB0(debug_eret); - if (env->hflags & MIPS_HFLAG_ERL) { + if (env->CP0_Status & (1 << CP0St_ERL)) { env->PC = env->CP0_ErrorEPC; - env->hflags &= ~MIPS_HFLAG_ERL; - env->CP0_Status &= ~(1 << CP0St_ERL); + env->CP0_Status &= ~(1 << CP0St_ERL); } else { env->PC = env->CP0_EPC; - env->hflags &= ~MIPS_HFLAG_EXL; - env->CP0_Status &= ~(1 << CP0St_EXL); + env->CP0_Status &= ~(1 << CP0St_EXL); } + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_UM))) + env->hflags |= MIPS_HFLAG_UM; env->CP0_LLAddr = 1; RETURN(); } @@ -2108,6 +2104,13 @@ void op_deret (void) { CALL_FROM_TB0(debug_eret); env->PC = env->CP0_DEPC; + env->hflags |= MIPS_HFLAG_DM; + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM) && + (env->CP0_Status & (1 << CP0St_UM))) + env->hflags |= MIPS_HFLAG_UM; + env->CP0_LLAddr = 1; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 8ab7bf57d..f9748fc16 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -509,9 +509,11 @@ void dump_sc (void) void debug_eret (void) { if (loglevel) { - fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx " ErrorEPC " TARGET_FMT_lx " (%d)\n", - env->PC, env->CP0_EPC, env->CP0_ErrorEPC, - env->hflags & MIPS_HFLAG_ERL ? 1 : 0); + fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + env->PC, env->CP0_EPC); + if (env->CP0_Status & (1 << CP0St_ERL)) + fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + fputs("\n", logfile); } } diff --git a/target-mips/translate.c b/target-mips/translate.c index 5cc922b57..65821087b 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4022,17 +4022,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) { const char *opn = "unk"; - if ((!ctx->CP0_Status & (1 << CP0St_CU0) && - (ctx->hflags & MIPS_HFLAG_UM)) && - !(ctx->hflags & MIPS_HFLAG_ERL) && - !(ctx->hflags & MIPS_HFLAG_EXL)) { - if (loglevel & CPU_LOG_TB_IN_ASM) { - fprintf(logfile, "CP0 is not usable\n"); - } - generate_exception (ctx, EXCP_CpU); - return; - } - switch (opc) { case OPC_MFC0: if (rt == 0) { @@ -4809,7 +4798,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: - /* treat as noop */ + /* treat as noop */ break; default: /* Invalid */ MIPS_INVAL("REGIMM"); @@ -4818,6 +4807,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) } break; case OPC_CP0: + gen_op_cp0_enabled(); op1 = MASK_CP0(ctx->opcode); switch (op1) { case OPC_MFC0: @@ -5258,12 +5248,6 @@ void cpu_dump_state (CPUState *env, FILE *f, } c0_status = env->CP0_Status; - if (env->hflags & MIPS_HFLAG_UM) - c0_status |= (1 << CP0St_UM); - if (env->hflags & MIPS_HFLAG_ERL) - c0_status |= (1 << CP0St_ERL); - if (env->hflags & MIPS_HFLAG_EXL) - c0_status |= (1 << CP0St_EXL); cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", c0_status, env->CP0_Cause, env->CP0_EPC); @@ -5304,6 +5288,7 @@ void cpu_reset (CPUMIPSState *env) } else { env->CP0_ErrorEPC = env->PC; } + env->hflags = 0; env->PC = (int32_t)0xBFC00000; #if defined (MIPS_USES_R4K_TLB) env->CP0_Random = MIPS_TLB_NB - 1; @@ -5314,7 +5299,6 @@ void cpu_reset (CPUMIPSState *env) env->CP0_EBase = 0x80000000; env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); env->CP0_WatchLo = 0; - env->hflags = MIPS_HFLAG_ERL; /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); #endif -- 2.39.2