Sanitize mips exception handling.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 30 Mar 2007 16:44:54 +0000 (16:44 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 30 Mar 2007 16:44:54 +0000 (16:44 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2546 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-exec.c
dyngen-exec.h
hw/mips_int.c
target-mips/cpu.h
target-mips/helper.c
target-mips/op.c
target-mips/op_helper.c
target-mips/translate.c

index d124c40..d168886 100644 (file)
@@ -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;
index bf40353..c63eb26 100644 (file)
@@ -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
index 7f9f153..b384b64 100644 (file)
@@ -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)
index f0f3ab2..4fec3cc 100644 (file)
@@ -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                */
index 0b23f35..fe5b2ab 100644 (file)
@@ -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;
index f97ec42..fecf18c 100644 (file)
@@ -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();
 }
 
index 8ab7bf5..f9748fc 100644 (file)
@@ -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);
     }
 }
 
index 5cc922b..6582108 100644 (file)
@@ -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