diff --git a/target/arm/helper.c b/target/arm/helper.c index dc4b4123e0..dc2471eda7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6522,6 +6522,19 @@ static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri, writefn(env, ri, value); } +static uint64_t el2_e2h_e12_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + /* Pass the EL1 register accessor its ri, not the EL12 alias ri */ + return ri->orig_readfn(env, ri->opaque); +} + +static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* Pass the EL1 register accessor its ri, not the EL12 alias ri */ + return ri->orig_writefn(env, ri->opaque, value); +} + static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) { struct E2HAlias { @@ -6621,6 +6634,28 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) new_reg->type |= ARM_CP_ALIAS; /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ new_reg->access &= PL2_RW | PL3_RW; + /* The new_reg op fields are as per new_key, not the target reg */ + new_reg->crn = (a->new_key & CP_REG_ARM64_SYSREG_CRN_MASK) + >> CP_REG_ARM64_SYSREG_CRN_SHIFT; + new_reg->crm = (a->new_key & CP_REG_ARM64_SYSREG_CRM_MASK) + >> CP_REG_ARM64_SYSREG_CRM_SHIFT; + new_reg->opc0 = (a->new_key & CP_REG_ARM64_SYSREG_OP0_MASK) + >> CP_REG_ARM64_SYSREG_OP0_SHIFT; + new_reg->opc1 = (a->new_key & CP_REG_ARM64_SYSREG_OP1_MASK) + >> CP_REG_ARM64_SYSREG_OP1_SHIFT; + new_reg->opc2 = (a->new_key & CP_REG_ARM64_SYSREG_OP2_MASK) + >> CP_REG_ARM64_SYSREG_OP2_SHIFT; + new_reg->opaque = src_reg; + new_reg->orig_readfn = src_reg->readfn ?: raw_read; + new_reg->orig_writefn = src_reg->writefn ?: raw_write; + if (!new_reg->raw_readfn) { + new_reg->raw_readfn = raw_read; + } + if (!new_reg->raw_writefn) { + new_reg->raw_writefn = raw_write; + } + new_reg->readfn = el2_e2h_e12_read; + new_reg->writefn = el2_e2h_e12_write; ok = g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)a->new_key, new_reg);