summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--linux-user/mips/target_cpu.h2
-rw-r--r--linux-user/syscall.c2
-rw-r--r--target-mips/cpu.h11
-rw-r--r--target-mips/machine.c16
-rw-r--r--target-mips/op_helper.c14
-rw-r--r--target-mips/translate.c55
6 files changed, 85 insertions, 15 deletions
diff --git a/linux-user/mips/target_cpu.h b/linux-user/mips/target_cpu.h
index ba8e9eb1f9..19b8855000 100644
--- a/linux-user/mips/target_cpu.h
+++ b/linux-user/mips/target_cpu.h
@@ -30,7 +30,7 @@ static inline void cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
 
 static inline void cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
 {
-    env->tls_value = newtls;
+    env->active_tc.CP0_UserLocal = newtls;
 }
 
 #endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c134c32d6f..7d7407920b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8702,7 +8702,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
 #if defined(TARGET_MIPS)
-      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+      ((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
       ret = 0;
       break;
 #elif defined(TARGET_CRIS)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index a9b2c7ae38..8b9a92ebdc 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -168,6 +168,7 @@ struct TCState {
     target_ulong CP0_TCSchedule;
     target_ulong CP0_TCScheFBack;
     int32_t CP0_Debug_tcstatus;
+    target_ulong CP0_UserLocal;
 };
 
 typedef struct CPUMIPSState CPUMIPSState;
@@ -362,6 +363,7 @@ struct CPUMIPSState {
     int32_t CP0_Config3;
 #define CP0C3_M    31
 #define CP0C3_ISA_ON_EXC 16
+#define CP0C3_ULRI 13
 #define CP0C3_DSPP 10
 #define CP0C3_LPA  7
 #define CP0C3_VEIC 6
@@ -470,6 +472,8 @@ struct CPUMIPSState {
     /* MIPS DSP resources access. */
 #define MIPS_HFLAG_DSP   0x40000  /* Enable access to MIPS DSP resources. */
 #define MIPS_HFLAG_DSPR2 0x80000  /* Enable access to MIPS DSPR2 resources. */
+    /* Extra flag about HWREna register. */
+#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */
     target_ulong btarget;        /* Jump / branch target               */
     target_ulong bcond;          /* Branch condition (if needed)       */
 
@@ -479,8 +483,6 @@ struct CPUMIPSState {
     uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
     int insn_flags; /* Supported instruction set */
 
-    target_ulong tls_value; /* For usermode emulation */
-
     CPU_COMMON
 
     /* Fields from here on are preserved across CPU reset. */
@@ -523,7 +525,7 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);
 extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env);
 
-#define CPU_SAVE_VERSION 3
+#define CPU_SAVE_VERSION 4
 
 /* MMU modes definitions. We carefully match the indices with our
    hflags layout. */
@@ -682,7 +684,8 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
 {
     *pc = env->active_tc.PC;
     *cs_base = 0;
-    *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
+    *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK |
+                            MIPS_HFLAG_HWRENA_ULR);
 }
 
 static inline int mips_vpe_active(CPUMIPSState *env)
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 0a07db8540..0496faa910 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -25,6 +25,7 @@ static void save_tc(QEMUFile *f, TCState *tc)
     qemu_put_betls(f, &tc->CP0_TCSchedule);
     qemu_put_betls(f, &tc->CP0_TCScheFBack);
     qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
+    qemu_put_betls(f, &tc->CP0_UserLocal);
 }
 
 static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
@@ -151,7 +152,7 @@ void cpu_save(QEMUFile *f, void *opaque)
         save_fpu(f, &env->fpus[i]);
 }
 
-static void load_tc(QEMUFile *f, TCState *tc)
+static void load_tc(QEMUFile *f, TCState *tc, int version_id)
 {
     int i;
 
@@ -173,6 +174,9 @@ static void load_tc(QEMUFile *f, TCState *tc)
     qemu_get_betls(f, &tc->CP0_TCSchedule);
     qemu_get_betls(f, &tc->CP0_TCScheFBack);
     qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
+    if (version_id >= 4) {
+        qemu_get_betls(f, &tc->CP0_UserLocal);
+    }
 }
 
 static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
@@ -194,11 +198,12 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     MIPSCPU *cpu = mips_env_get_cpu(env);
     int i;
 
-    if (version_id != 3)
+    if (version_id < 3) {
         return -EINVAL;
+    }
 
     /* Load active TC */
-    load_tc(f, &env->active_tc);
+    load_tc(f, &env->active_tc, version_id);
 
     /* Load active FPU */
     load_fpu(f, &env->active_fpu);
@@ -298,8 +303,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_sbe32s(f, &env->CP0_DESAVE);
 
     /* Load inactive TC state */
-    for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
-        load_tc(f, &env->tcs[i]);
+    for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) {
+        load_tc(f, &env->tcs[i], version_id);
+    }
     for (i = 0; i < MIPS_FPU_MAX; i++)
         load_fpu(f, &env->fpus[i]);
 
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 4704216834..27651a4a00 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1297,7 +1297,19 @@ void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
 
 void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
 {
-    env->CP0_HWREna = arg1 & 0x0000000F;
+    uint32_t mask = 0x0000000F;
+
+    if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
+        mask |= (1 << 29);
+
+        if (arg1 & (1 << 29)) {
+            env->hflags |= MIPS_HFLAG_HWRENA_ULR;
+        } else {
+            env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
+        }
+    }
+
+    env->CP0_HWREna = arg1 & mask;
 }
 
 void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 76deb7b138..2b3befb0b4 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1072,6 +1072,7 @@ typedef struct DisasContext {
     uint32_t hflags, saved_hflags;
     int bstate;
     target_ulong btarget;
+    bool ulri;
 } DisasContext;
 
 enum {
@@ -4215,7 +4216,18 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
         case 1:
 //            gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
             rn = "ContextConfig";
+            goto die;
 //            break;
+        case 2:
+            if (ctx->ulri) {
+                tcg_gen_ld32s_tl(arg, cpu_env,
+                                 offsetof(CPUMIPSState,
+                                          active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            } else {
+                tcg_gen_movi_tl(arg, 0);
+            }
+            break;
         default:
             goto die;
         }
@@ -4802,7 +4814,15 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
         case 1:
 //            gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
             rn = "ContextConfig";
+            goto die;
 //            break;
+        case 2:
+            if (ctx->ulri) {
+                tcg_gen_st_tl(arg, cpu_env,
+                              offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            }
+            break;
         default:
             goto die;
         }
@@ -4862,6 +4882,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
         case 0:
             check_insn(ctx, ISA_MIPS32R2);
             gen_helper_mtc0_hwrena(cpu_env, arg);
+            ctx->bstate = BS_STOP;
             rn = "HWREna";
             break;
         default:
@@ -5406,7 +5427,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
         case 1:
 //            gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
             rn = "ContextConfig";
+            goto die;
 //            break;
+        case 2:
+            if (ctx->ulri) {
+                tcg_gen_ld_tl(arg, cpu_env,
+                              offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            } else {
+                tcg_gen_movi_tl(arg, 0);
+            }
+            break;
         default:
             goto die;
         }
@@ -5978,7 +6009,15 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
         case 1:
 //           gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
             rn = "ContextConfig";
+            goto die;
 //           break;
+        case 2:
+            if (ctx->ulri) {
+                tcg_gen_st_tl(arg, cpu_env,
+                              offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            }
+            break;
         default:
             goto die;
         }
@@ -6038,6 +6077,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
         case 0:
             check_insn(ctx, ISA_MIPS32R2);
             gen_helper_mtc0_hwrena(cpu_env, arg);
+            ctx->bstate = BS_STOP;
             rn = "HWREna";
             break;
         default:
@@ -9060,12 +9100,20 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
         break;
     case 29:
 #if defined(CONFIG_USER_ONLY)
-        tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUMIPSState, tls_value));
+        tcg_gen_ld_tl(t0, cpu_env,
+                      offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
         gen_store_gpr(t0, rt);
         break;
 #else
-        /* XXX: Some CPUs implement this in hardware.
-           Not supported yet. */
+        if ((ctx->hflags & MIPS_HFLAG_CP0) ||
+            (ctx->hflags & MIPS_HFLAG_HWRENA_ULR)) {
+            tcg_gen_ld_tl(t0, cpu_env,
+                          offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
+            gen_store_gpr(t0, rt);
+        } else {
+            generate_exception(ctx, EXCP_RI);
+        }
+        break;
 #endif
     default:            /* Invalid */
         MIPS_INVAL("rdhwr");
@@ -15609,6 +15657,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
     ctx.bstate = BS_NONE;
     /* Restore delay slot state from the tb context.  */
     ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
+    ctx.ulri = env->CP0_Config3 & (1 << CP0C3_ULRI);
     restore_cpu_state(env, &ctx);
 #ifdef CONFIG_USER_ONLY
         ctx.mem_idx = MIPS_HFLAG_UM;