qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [RFC PATCH 15/21] target-arm: add banked coprocessor regist


From: Sergey Fedorov
Subject: [Qemu-devel] [RFC PATCH 15/21] target-arm: add banked coprocessor register type
Date: Tue, 03 Dec 2013 12:48:49 +0400

Banked CP registers are defined with BANKED_CP_REG macro which defines
an active register state field followed by an adjacent banked register
state array field. An active CP register state is accessed as usual
through an active state field. Banked CP register state is save in
banked register state array. The array is indexed by NS bit value.

When translating a banked CP register access instruction in secure
state, SCR.NS bit determines which field should be used. If SCR.NS bit
is set then a non-secure banked value is used instead of an active one.
That is possible only in monitor CPU mode. In non-secure state an active
register state field is always used.

Signed-off-by: Sergey Fedorov <address@hidden>
---
 target-arm/cpu.h       |   14 ++++++++++-
 target-arm/translate.c |   60 ++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 69 insertions(+), 5 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a20f354..fe3a646 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -73,6 +73,17 @@ typedef void ARMWriteCPFunc(void *opaque, int cp_info,
 typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
                                int dstreg, int operand);
 
+/* Define a banked coprocessor register state field. Use %name as the active
+ * register state field name. The banked register state array field name has
+ * "banked_" prefix. The banked register state array indexes corresponds to
+ * SCR.NS bit value.
+ */
+#define BANKED_CP_REG(type, name) \
+    struct { \
+        type name; \
+        type banked_##name[2]; \
+    }
+
 struct arm_boot_info;
 
 #define NB_MMU_MODES 4
@@ -572,13 +583,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 #define ARM_CP_OVERRIDE 16
 #define ARM_CP_NO_MIGRATE 32
 #define ARM_CP_IO 64
+#define ARM_CP_BANKED 128
 #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
 #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
 #define ARM_LAST_SPECIAL ARM_CP_WFI
 /* Used only as a terminator for ARMCPRegInfo lists */
 #define ARM_CP_SENTINEL 0xffff
 /* Mask of only the flag bits in a type field */
-#define ARM_CP_FLAG_MASK 0x7f
+#define ARM_CP_FLAG_MASK 0xff
 
 /* Return true if cptype is a valid type field. This is used to try to
  * catch errors where the sentinel has been accidentally left off the end
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 8548a4c..345866c 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6389,9 +6389,22 @@ static int disas_coproc_insn(CPUARMState * env, 
DisasContext *s, uint32_t insn)
                     tmpptr = tcg_const_ptr(ri);
                     gen_helper_get_cp_reg64(tmp64, cpu_env, tmpptr);
                     tcg_temp_free_ptr(tmpptr);
-                } else {
+                } else if (!(ri->type & ARM_CP_BANKED) || IS_NS(s)) {
                     tmp64 = tcg_temp_new_i64();
                     tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset);
+                } else {
+                    TCGv_ptr tmpptr;
+                    tmp = load_cpu_field(cp15.c1_scr);
+                    tcg_gen_andi_i32(tmp, tmp, 1);
+                    tcg_gen_shli_i32(tmp, tmp, 4);
+                    tmpptr = tcg_temp_new_ptr();
+                    tcg_gen_ext_i32_ptr(tmpptr, cpu_env);
+                    tcg_gen_addi_ptr(tmpptr, cpu_env, ri->fieldoffset);
+                    tcg_gen_add_ptr(tmpptr, tmpptr, tmp);
+                    tcg_temp_free_i32(tmp);
+                    tmp64 = tcg_temp_new_i64();
+                    tcg_gen_ld_i64(tmp64, tmpptr, 0);
+                    tcg_temp_free_ptr(tmpptr);
                 }
                 tmp = tcg_temp_new_i32();
                 tcg_gen_trunc_i64_i32(tmp, tmp64);
@@ -6412,8 +6425,19 @@ static int disas_coproc_insn(CPUARMState * env, 
DisasContext *s, uint32_t insn)
                     tmpptr = tcg_const_ptr(ri);
                     gen_helper_get_cp_reg(tmp, cpu_env, tmpptr);
                     tcg_temp_free_ptr(tmpptr);
-                } else {
+                } else if (!(ri->type & ARM_CP_BANKED) || IS_NS(s)) {
                     tmp = load_cpu_offset(ri->fieldoffset);
+                } else {
+                    TCGv_ptr tmpptr;
+                    tmp = load_cpu_field(cp15.c1_scr);
+                    tcg_gen_andi_i32(tmp, tmp, 1);
+                    tcg_gen_shli_i32(tmp, tmp, 2);
+                    tmpptr = tcg_temp_new_ptr();
+                    tcg_gen_ext_i32_ptr(tmpptr, cpu_env);
+                    tcg_gen_addi_ptr(tmpptr, cpu_env, ri->fieldoffset);
+                    tcg_gen_add_ptr(tmpptr, tmpptr, tmp);
+                    tcg_gen_ld_i32(tmp, tmpptr, 0);
+                    tcg_temp_free_ptr(tmpptr);
                 }
                 if (rt == 15) {
                     /* Destination register of r15 for 32 bit loads sets
@@ -6445,8 +6469,22 @@ static int disas_coproc_insn(CPUARMState * env, 
DisasContext *s, uint32_t insn)
                     gen_set_pc_im(s, s->pc);
                     gen_helper_set_cp_reg64(cpu_env, tmpptr, tmp64);
                     tcg_temp_free_ptr(tmpptr);
-                } else {
+                } else if (!(ri->type & ARM_CP_BANKED) || IS_NS(s)) {
                     tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset);
+                } else {
+                    TCGv_i32 tmp;
+                    TCGv_ptr tmpptr;
+                    tmp = load_cpu_field(cp15.c1_scr);
+                    tcg_gen_andi_i32(tmp, tmp, 1);
+                    tcg_gen_shli_i32(tmp, tmp, 4);
+                    tmpptr = tcg_temp_new_ptr();
+                    tcg_gen_ext_i32_ptr(tmpptr, cpu_env);
+                    tcg_gen_addi_ptr(tmpptr, cpu_env, ri->fieldoffset);
+                    tcg_gen_add_ptr(tmpptr, tmpptr, tmp);
+                    tcg_temp_free_i32(tmp);
+                    tmp64 = tcg_temp_new_i64();
+                    tcg_gen_st_i64(tmp64, tmpptr, 0);
+                    tcg_temp_free_ptr(tmpptr);
                 }
                 tcg_temp_free_i64(tmp64);
             } else {
@@ -6459,9 +6497,23 @@ static int disas_coproc_insn(CPUARMState * env, 
DisasContext *s, uint32_t insn)
                     gen_helper_set_cp_reg(cpu_env, tmpptr, tmp);
                     tcg_temp_free_ptr(tmpptr);
                     tcg_temp_free_i32(tmp);
-                } else {
+                } else if (!(ri->type & ARM_CP_BANKED) || IS_NS(s)) {
                     TCGv_i32 tmp = load_reg(s, rt);
                     store_cpu_offset(tmp, ri->fieldoffset);
+                } else {
+                    TCGv_i32 tmp;
+                    TCGv_ptr tmpptr;
+                    tmp = load_cpu_field(cp15.c1_scr);
+                    tcg_gen_andi_i32(tmp, tmp, 1);
+                    tcg_gen_shli_i32(tmp, tmp, 2);
+                    tmpptr = tcg_temp_new_ptr();
+                    tcg_gen_ext_i32_ptr(tmpptr, cpu_env);
+                    tcg_gen_addi_ptr(tmpptr, cpu_env, ri->fieldoffset);
+                    tcg_gen_add_ptr(tmpptr, tmpptr, tmp);
+                    load_reg_var(s, tmp, rt);
+                    tcg_gen_st_i32(tmp, tmpptr, 0);
+                    tcg_temp_free_ptr(tmpptr);
+                    tcg_temp_free_i32(tmp);
                 }
             }
         }
-- 
1.7.9.5




reply via email to

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