qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [v2 PATCH] target-mips: implement UserLocal Register


From: Petar Jovanovic
Subject: [Qemu-devel] [v2 PATCH] target-mips: implement UserLocal Register
Date: Mon, 26 May 2014 19:28:41 +0200

From: Petar Jovanovic <address@hidden>

>From MIPS documentation (Volume III):

UserLocal Register (CP0 Register 4, Select 2)
Compliance Level: Recommended.

The UserLocal register is a read-write register that is not interpreted by
the hardware and conditionally readable via the RDHWR instruction.

This register only exists if the Config3-ULRI register field is set.

Privileged software may write this register with arbitrary information and
make it accessable to unprivileged software via register 29 (ULR) of the
RDHWR instruction. To do so, bit 29 of the HWREna register must be set to a
1 to enable unprivileged access to the register.

Signed-off-by: Petar Jovanovic <address@hidden>
---
v2:
- Defined MIPS_HFLAG_CP0UL flag, checks are now based on hflags
- CP0_UserLocal moved to struct TCState
- Added tc->CP0_UserLocal in save_tc/load_tc in target-mips/machine.c
- Reused CP0_UserLocal field for user-mode purpose

 linux-user/mips/target_cpu.h |    2 +-
 linux-user/syscall.c         |    2 +-
 target-mips/cpu.h            |   13 +++++++++---
 target-mips/helper.h         |    1 +
 target-mips/machine.c        |    2 ++
 target-mips/op_helper.c      |   20 ++++++++++++++++++-
 target-mips/translate.c      |   45 +++++++++++++++++++++++++++++++++++++++---
 7 files changed, 76 insertions(+), 9 deletions(-)

diff --git a/linux-user/mips/target_cpu.h b/linux-user/mips/target_cpu.h
index ba8e9eb..19b8855 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 6efeeff..fda8dd6 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8686,7 +8686,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 6c2014e..caded51 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -167,6 +167,7 @@ struct TCState {
     target_ulong CP0_TCSchedule;
     target_ulong CP0_TCScheFBack;
     int32_t CP0_Debug_tcstatus;
+    target_ulong CP0_UserLocal;
 };
 
 typedef struct CPUMIPSState CPUMIPSState;
@@ -361,6 +362,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
@@ -469,6 +471,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 flags about implemented registers. */
+#define MIPS_HFLAG_CP0UL 0x100000 /* CP0_UserLocal register implemented. */
     target_ulong btarget;        /* Jump / branch target               */
     target_ulong bcond;          /* Branch condition (if needed)       */
 
@@ -478,8 +482,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. */
@@ -681,7 +683,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_CP0UL);
 }
 
 static inline int mips_vpe_active(CPUMIPSState *env)
@@ -779,6 +782,10 @@ static inline void compute_hflags(CPUMIPSState *env)
             env->hflags |= MIPS_HFLAG_COP1X;
         }
     }
+
+    if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
+        env->hflags |= MIPS_HFLAG_CP0UL;
+    }
 }
 
 #endif /* !defined (__MIPS_CPU_H__) */
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 8c7921a..ec56199 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -296,6 +296,7 @@ DEF_HELPER_1(rdhwr_cpunum, tl, env)
 DEF_HELPER_1(rdhwr_synci_step, tl, env)
 DEF_HELPER_1(rdhwr_cc, tl, env)
 DEF_HELPER_1(rdhwr_ccres, tl, env)
+DEF_HELPER_1(rdhwr_ul, tl, env)
 DEF_HELPER_2(pmon, void, env, int)
 DEF_HELPER_1(wait, void, env)
 
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 0a07db8..cbd9d7a 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)
@@ -173,6 +174,7 @@ 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);
+    qemu_get_betls(f, &tc->CP0_UserLocal);
 }
 
 static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 4edec6c..8b6eea8 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1301,7 +1301,13 @@ 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 |= 0x20000000;
+    }
+
+    env->CP0_HWREna = arg1 & mask;
 }
 
 void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
@@ -2091,6 +2097,18 @@ target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
     return 0;
 }
 
+target_ulong helper_rdhwr_ul(CPUMIPSState *env)
+{
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 29))) {
+        return env->active_tc.CP0_UserLocal;
+    } else {
+        helper_raise_exception(env, EXCP_RI);
+    }
+
+    return 0;
+}
+
 void helper_pmon(CPUMIPSState *env, int function)
 {
     function /= 2;
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 05f82d2..6b0bf08 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -4215,7 +4215,17 @@ 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->hflags & MIPS_HFLAG_CP0UL) {
+                tcg_gen_ld32s_tl(arg, cpu_env,
+                                 offsetof(CPUMIPSState,
+                                          active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            } else {
+                tcg_gen_movi_tl(arg, 0);
+            }
         default:
             goto die;
         }
@@ -4802,7 +4812,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->hflags & MIPS_HFLAG_CP0UL) {
+                tcg_gen_st_tl(arg, cpu_env,
+                              offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            }
+            break;
         default:
             goto die;
         }
@@ -5406,7 +5424,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->hflags & MIPS_HFLAG_CP0UL) {
+                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 +6006,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->hflags & MIPS_HFLAG_CP0UL) {
+                tcg_gen_st_tl(arg, cpu_env,
+                              offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
+                rn = "UserLocal";
+            }
+            break;
         default:
             goto die;
         }
@@ -9060,12 +9096,15 @@ 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. */
+        save_cpu_state(ctx, 1);
+        gen_helper_rdhwr_ul(t0, cpu_env);
+        gen_store_gpr(t0, rt);
+        break;
 #endif
     default:            /* Invalid */
         MIPS_INVAL("rdhwr");
-- 
1.7.9.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]