@@ -1061,27 +1061,13 @@ uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
return (Aff1 << ARM_AFF1_SHIFT) | Aff0;
}
-static void cpreg_hashtable_data_destroy(gpointer data)
-{
- /*
- * Destroy function for cpu->cp_regs hashtable data entries.
- * We must free the name string because it was g_strdup()ed in
- * add_cpreg_to_hashtable(). It's OK to cast away the 'const'
- * from r->name because we know we definitely allocated it.
- */
- ARMCPRegInfo *r = data;
-
- g_free((void *)r->name);
- g_free(r);
-}
-
static void arm_cpu_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
cpu_set_cpustate_pointers(cpu);
cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, cpreg_hashtable_data_destroy);
+ NULL, g_free);
QLIST_INIT(&cpu->pre_el_change_hooks);
QLIST_INIT(&cpu->el_change_hooks);
@@ -8509,37 +8509,90 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
return cpu_list;
}
+/*
+ * Private utility function for define_one_arm_cp_reg_with_opaque():
+ * add a single reginfo struct to the hash table.
+ */
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
void *opaque, CPState state,
CPSecureState secstate,
int crm, int opc1, int opc2,
const char *name)
{
- /* Private utility function for define_one_arm_cp_reg_with_opaque():
- * add a single reginfo struct to the hash table.
- */
uint32_t key;
- ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
- int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
- int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
+ ARMCPRegInfo *r2;
+ bool is64 = r->type & ARM_CP_64BIT;
+ bool ns = secstate & ARM_CP_SECSTATE_NS;
+ int cp = r->cp;
+ bool isbanked;
+ size_t name_len;
- r2->name = g_strdup(name);
- /* Reset the secure state to the specific incoming state. This is
- * necessary as the register may have been defined with both states.
+ switch (state) {
+ case ARM_CP_STATE_AA32:
+ /* We assume it is a cp15 register if the .cp field is left unset. */
+ if (cp == 0 && r->state == ARM_CP_STATE_BOTH) {
+ cp = 15;
+ }
+ key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2);
+ break;
+ case ARM_CP_STATE_AA64:
+ /*
+ * To allow abbreviation of ARMCPRegInfo definitions, we treat
+ * cp == 0 as equivalent to the value for "standard guest-visible
+ * sysreg". STATE_BOTH definitions are also always "standard sysreg"
+ * in their AArch64 view (the .cp value may be non-zero for the
+ * benefit of the AArch32 view).
+ */
+ if (cp == 0 || r->state == ARM_CP_STATE_BOTH) {
+ cp = CP_REG_ARM64_SYSREG_CP;
+ }
+ key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Overriding of an existing definition must be explicitly requested. */
+ if (!(r->type & ARM_CP_OVERRIDE)) {
+ const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
+ if (oldreg) {
+ assert(oldreg->type & ARM_CP_OVERRIDE);
+ }
+ }
+
+ /* Combine cpreg and name into one allocation. */
+ name_len = strlen(name) + 1;
+ r2 = g_malloc(sizeof(*r2) + name_len);
+ *r2 = *r;
+ r2->name = memcpy(r2 + 1, name, name_len);
+
+ /*
+ * Update fields to match the instantiation, overwiting wildcards
+ * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH.
*/
+ r2->cp = cp;
+ r2->crm = crm;
+ r2->opc1 = opc1;
+ r2->opc2 = opc2;
+ r2->state = state;
r2->secure = secstate;
+ if (opaque) {
+ r2->opaque = opaque;
+ }
- if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
- /* Register is banked (using both entries in array).
+ isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1];
+ if (isbanked) {
+ /*
+ * Register is banked (using both entries in array).
* Overwriting fieldoffset as the array is only used to define
* banked registers but later only fieldoffset is used.
*/
r2->fieldoffset = r->bank_fieldoffsets[ns];
}
-
if (state == ARM_CP_STATE_AA32) {
- if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
- /* If the register is banked then we don't need to migrate or
+ if (isbanked) {
+ /*
+ * If the register is banked then we don't need to migrate or
* reset the 32-bit instance in certain cases:
*
* 1) If the register has both 32-bit and 64-bit instances then we
@@ -8554,56 +8607,22 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
r2->type |= ARM_CP_ALIAS;
}
} else if ((secstate != r->secure) && !ns) {
- /* The register is not banked so we only want to allow migration of
- * the non-secure instance.
+ /*
+ * The register is not banked so we only want to allow migration
+ * of the non-secure instance.
*/
r2->type |= ARM_CP_ALIAS;
}
- if (r->state == ARM_CP_STATE_BOTH) {
- /* We assume it is a cp15 register if the .cp field is left unset.
- */
- if (r2->cp == 0) {
- r2->cp = 15;
- }
-
+ if (r->state == ARM_CP_STATE_BOTH && r->fieldoffset) {
#ifdef HOST_WORDS_BIGENDIAN
- if (r2->fieldoffset) {
- r2->fieldoffset += sizeof(uint32_t);
- }
+ r2->fieldoffset += sizeof(uint32_t);
#endif
}
}
- if (state == ARM_CP_STATE_AA64) {
- /* To allow abbreviation of ARMCPRegInfo
- * definitions, we treat cp == 0 as equivalent to
- * the value for "standard guest-visible sysreg".
- * STATE_BOTH definitions are also always "standard
- * sysreg" in their AArch64 view (the .cp value may
- * be non-zero for the benefit of the AArch32 view).
- */
- if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) {
- r2->cp = CP_REG_ARM64_SYSREG_CP;
- }
- key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
- r2->opc0, opc1, opc2);
- } else {
- key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2);
- }
- if (opaque) {
- r2->opaque = opaque;
- }
- /* reginfo passed to helpers is correct for the actual access,
- * and is never ARM_CP_STATE_BOTH:
- */
- r2->state = state;
- /* Make sure reginfo passed to helpers for wildcarded regs
- * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
- */
- r2->crm = crm;
- r2->opc1 = opc1;
- r2->opc2 = opc2;
- /* By convention, for wildcarded registers only the first
+
+ /*
+ * By convention, for wildcarded registers only the first
* entry is used for migration; the others are marked as
* ALIAS so we don't try to transfer the register
* multiple times. Special registers (ie NOP/WFI) are
@@ -8612,13 +8631,14 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
if (r->type & ARM_CP_SPECIAL_MASK) {
r2->type |= ARM_CP_NO_RAW;
}
- if (((r->crm == CP_ANY) && crm != 0) ||
- ((r->opc1 == CP_ANY) && opc1 != 0) ||
- ((r->opc2 == CP_ANY) && opc2 != 0)) {
+ if ((r->crm == CP_ANY && crm != 0) ||
+ (r->opc1 == CP_ANY && opc1 != 0) ||
+ (r->opc2 == CP_ANY && opc2 != 0)) {
r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
}
- /* Check that raw accesses are either forbidden or handled. Note that
+ /*
+ * Check that raw accesses are either forbidden or handled. Note that
* we can't assert this earlier because the setup of fieldoffset for
* banked registers has to be done first.
*/
@@ -8626,20 +8646,6 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
assert(!raw_accessors_invalid(r2));
}
- /* Overriding of an existing definition must be explicitly
- * requested.
- */
- if (!(r->type & ARM_CP_OVERRIDE)) {
- const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
- if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
- fprintf(stderr, "Register redefined: cp=%d %d bit "
- "crn=%d crm=%d opc1=%d opc2=%d, "
- "was %s, now %s\n", r2->cp, 32 + 32 * is64,
- r2->crn, r2->crm, r2->opc1, r2->opc2,
- oldreg->name, r2->name);
- g_assert_not_reached();
- }
- }
g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2);
}
Use a single memory allocation for name and reginfo. Perform the override check early; use assert not printf+abort. Use a switch statement to validate state. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/cpu.c | 16 +---- target/arm/helper.c | 154 +++++++++++++++++++++++--------------------- 2 files changed, 81 insertions(+), 89 deletions(-)