diff options
Diffstat (limited to 'target-arm/helper.c')
-rw-r--r-- | target-arm/helper.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c index 5f639fdeb8..aeae024165 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -222,15 +222,23 @@ static gint cpreg_key_compare(gconstpointer a, gconstpointer b) return aidx - bidx; } +static void cpreg_make_keylist(gpointer key, gpointer value, gpointer udata) +{ + GList **plist = udata; + + *plist = g_list_prepend(*plist, key); +} + void init_cpreg_list(ARMCPU *cpu) { /* Initialise the cpreg_tuples[] array based on the cp_regs hash. * Note that we require cpreg_tuples[] to be sorted by key ID. */ - GList *keys; + GList *keys = NULL; int arraylen; - keys = g_hash_table_get_keys(cpu->cp_regs); + g_hash_table_foreach(cpu->cp_regs, cpreg_make_keylist, &keys); + keys = g_list_sort(keys, cpreg_key_compare); cpu->cpreg_array_len = 0; @@ -891,6 +899,8 @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = { static int vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + int maskshift = extract32(value, 0, 3); + if (arm_feature(env, ARM_FEATURE_LPAE)) { value &= ~((7 << 19) | (3 << 14) | (0xf << 3)); } else { @@ -902,8 +912,8 @@ static int vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, * and the c2_mask and c2_base_mask values are meaningless. */ env->cp15.c2_control = value; - env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> value); - env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> value); + env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> maskshift); + env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> maskshift); return 0; } @@ -1378,9 +1388,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_DUMMY_C15_REGS)) { define_arm_cp_regs(cpu, dummy_c15_cp_reginfo); } - if (arm_feature(env, ARM_FEATURE_MPIDR)) { - define_arm_cp_regs(cpu, mpidr_cp_reginfo); - } if (arm_feature(env, ARM_FEATURE_LPAE)) { define_arm_cp_regs(cpu, lpae_cp_reginfo); } @@ -1393,12 +1400,17 @@ void register_cp_regs_for_features(ARMCPU *cpu) /* Note that the MIDR isn't a simple constant register because * of the TI925 behaviour where writes to another register can * cause the MIDR value to change. + * + * Unimplemented registers in the c15 0 0 0 space default to + * MIDR. Define MIDR first as this entire space, then CTR, TCMTR + * and friends override accordingly. */ { .name = "MIDR", - .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0, + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = CP_ANY, .access = PL1_R, .resetvalue = cpu->midr, .writefn = arm_cp_write_ignore, .raw_writefn = raw_write, - .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid) }, + .fieldoffset = offsetof(CPUARMState, cp15.c0_cpuid), + .type = ARM_CP_OVERRIDE }, { .name = "CTR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->ctr }, @@ -1435,21 +1447,20 @@ void register_cp_regs_for_features(ARMCPU *cpu) arm_feature(env, ARM_FEATURE_STRONGARM)) { ARMCPRegInfo *r; /* Register the blanket "writes ignored" value first to cover the - * whole space. Then define the specific ID registers, but update - * their access field to allow write access, so that they ignore - * writes rather than causing them to UNDEF. + * whole space. Then update the specific ID registers to allow write + * access, so that they ignore writes rather than causing them to + * UNDEF. */ define_one_arm_cp_reg(cpu, &crn0_wi_reginfo); for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) { r->access = PL1_RW; - define_one_arm_cp_reg(cpu, r); } - } else { - /* Just register the standard ID registers (read-only, meaning - * that writes will UNDEF). - */ - define_arm_cp_regs(cpu, id_cp_reginfo); } + define_arm_cp_regs(cpu, id_cp_reginfo); + } + + if (arm_feature(env, ARM_FEATURE_MPIDR)) { + define_arm_cp_regs(cpu, mpidr_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_AUXCR)) { @@ -1607,7 +1618,9 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo)); int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0; *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2); - r2->opaque = opaque; + if (opaque) { + r2->opaque = opaque; + } /* Make sure reginfo passed to helpers for wildcarded regs * has the correct crm/opc1/opc2 for this reg, not CP_ANY: */ |