@@ -79,11 +79,12 @@ DEF_HELPER_2(v8m_stackcheck, void, env, i32)
DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32)
-DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
-DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
-DEF_HELPER_2(get_cp_reg, i32, env, ptr)
-DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
-DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
+DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32)
+DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32)
+DEF_HELPER_3(set_cp_reg, void, env, cptr, i32)
+DEF_HELPER_2(get_cp_reg, i32, env, cptr)
+DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64)
+DEF_HELPER_2(get_cp_reg64, i64, env, cptr)
DEF_HELPER_2(get_r13_banked, i32, env, i32)
DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
@@ -610,6 +610,13 @@ static inline void set_disas_label(DisasContext *s, DisasLabel l)
s->pc_save = l.pc_save;
}
+static inline TCGv_ptr gen_lookup_cp_reg(uint32_t key)
+{
+ TCGv_ptr ret = tcg_temp_new_ptr();
+ gen_helper_lookup_cp_reg(ret, cpu_env, tcg_constant_i32(key));
+ return ret;
+}
+
/*
* Helpers for implementing sets of trans_* functions.
* Defer the implementation of NAME to FUNC, with optional extra arguments.
@@ -624,14 +624,16 @@ uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno)
}
}
-void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
- uint32_t isread)
+const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
+ uint32_t syndrome, uint32_t isread)
{
ARMCPU *cpu = env_archcpu(env);
- const ARMCPRegInfo *ri = rip;
+ const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key);
CPAccessResult res = CP_ACCESS_OK;
int target_el;
+ assert(ri != NULL);
+
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
res = CP_ACCESS_TRAP;
@@ -663,7 +665,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
res = ri->accessfn(env, ri, isread);
}
if (likely(res == CP_ACCESS_OK)) {
- return;
+ return ri;
}
fail:
@@ -705,7 +707,16 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
raise_exception(env, EXCP_UDEF, syndrome, target_el);
}
-void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
+const void *HELPER(lookup_cp_reg)(CPUARMState *env, uint32_t key)
+{
+ ARMCPU *cpu = env_archcpu(env);
+ const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key);
+
+ assert(ri != NULL);
+ return ri;
+}
+
+void HELPER(set_cp_reg)(CPUARMState *env, const void *rip, uint32_t value)
{
const ARMCPRegInfo *ri = rip;
@@ -718,7 +729,7 @@ void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
}
}
-uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
+uint32_t HELPER(get_cp_reg)(CPUARMState *env, const void *rip)
{
const ARMCPRegInfo *ri = rip;
uint32_t res;
@@ -734,7 +745,7 @@ uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
return res;
}
-void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
+void HELPER(set_cp_reg64)(CPUARMState *env, const void *rip, uint64_t value)
{
const ARMCPRegInfo *ri = rip;
@@ -747,7 +758,7 @@ void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
}
}
-uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
+uint64_t HELPER(get_cp_reg64)(CPUARMState *env, const void *rip)
{
const ARMCPRegInfo *ri = rip;
uint64_t res;
@@ -1944,13 +1944,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
unsigned int op0, unsigned int op1, unsigned int op2,
unsigned int crn, unsigned int crm, unsigned int rt)
{
- const ARMCPRegInfo *ri;
+ uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
+ crn, crm, op0, op1, op2);
+ const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
+ TCGv_ptr tcg_ri = NULL;
TCGv_i64 tcg_rt;
- ri = get_arm_cp_reginfo(s->cp_regs,
- ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
- crn, crm, op0, op1, op2));
-
if (!ri) {
/* Unknown register; this might be a guest error or a QEMU
* unimplemented feature.
@@ -1976,8 +1975,9 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
gen_a64_update_pc(s, 0);
- gen_helper_access_check_cp_reg(cpu_env,
- tcg_constant_ptr(ri),
+ tcg_ri = tcg_temp_new_ptr();
+ gen_helper_access_check_cp_reg(tcg_ri, cpu_env,
+ tcg_constant_i32(key),
tcg_constant_i32(syndrome),
tcg_constant_i32(isread));
} else if (ri->type & ARM_CP_RAISES_EXC) {
@@ -1993,7 +1993,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
case 0:
break;
case ARM_CP_NOP:
- return;
+ goto exit;
case ARM_CP_NZCV:
tcg_rt = cpu_reg(s, rt);
if (isread) {
@@ -2001,14 +2001,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
} else {
gen_set_nzcv(tcg_rt);
}
- return;
+ goto exit;
case ARM_CP_CURRENTEL:
/* Reads as current EL value from pstate, which is
* guaranteed to be constant by the tb flags.
*/
tcg_rt = cpu_reg(s, rt);
tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
- return;
+ goto exit;
case ARM_CP_DC_ZVA:
/* Writes clear the aligned block of memory which rt points into. */
if (s->mte_active[0]) {
@@ -2025,7 +2025,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
tcg_rt = clean_data_tbi(s, cpu_reg(s, rt));
}
gen_helper_dc_zva(cpu_env, tcg_rt);
- return;
+ goto exit;
case ARM_CP_DC_GVA:
{
TCGv_i64 clean_addr, tag;
@@ -2046,7 +2046,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
tcg_temp_free_i64(tag);
}
}
- return;
+ goto exit;
case ARM_CP_DC_GZVA:
{
TCGv_i64 clean_addr, tag;
@@ -2064,16 +2064,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
tcg_temp_free_i64(tag);
}
}
- return;
+ goto exit;
default:
g_assert_not_reached();
}
if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
- return;
+ goto exit;
} else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
- return;
+ goto exit;
} else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
- return;
+ goto exit;
}
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
@@ -2086,16 +2086,22 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
if (ri->type & ARM_CP_CONST) {
tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
} else if (ri->readfn) {
- gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_constant_ptr(ri));
+ if (!tcg_ri) {
+ tcg_ri = gen_lookup_cp_reg(key);
+ }
+ gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_ri);
} else {
tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
}
} else {
if (ri->type & ARM_CP_CONST) {
/* If not forbidden by access permissions, treat as WI */
- return;
+ goto exit;
} else if (ri->writefn) {
- gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tcg_rt);
+ if (!tcg_ri) {
+ tcg_ri = gen_lookup_cp_reg(key);
+ }
+ gen_helper_set_cp_reg64(cpu_env, tcg_ri, tcg_rt);
} else {
tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
}
@@ -2118,6 +2124,11 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
*/
s->base.is_jmp = DISAS_UPDATE_EXIT;
}
+
+ exit:
+ if (tcg_ri) {
+ tcg_temp_free_ptr(tcg_ri);
+ }
}
/* System
@@ -4714,12 +4714,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
int opc1, int crn, int crm, int opc2,
bool isread, int rt, int rt2)
{
- const ARMCPRegInfo *ri;
+ uint32_t key = ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2);
+ const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
+ TCGv_ptr tcg_ri = NULL;
bool need_exit_tb;
- ri = get_arm_cp_reginfo(s->cp_regs,
- ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
-
if (!ri) {
/*
* Unknown register; this might be a guest error or a QEMU
@@ -4800,8 +4799,9 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
gen_set_condexec(s);
gen_update_pc(s, 0);
- gen_helper_access_check_cp_reg(cpu_env,
- tcg_constant_ptr(ri),
+ tcg_ri = tcg_temp_new_ptr();
+ gen_helper_access_check_cp_reg(tcg_ri, cpu_env,
+ tcg_constant_i32(key),
tcg_constant_i32(syndrome),
tcg_constant_i32(isread));
} else if (ri->type & ARM_CP_RAISES_EXC) {
@@ -4818,15 +4818,15 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
case 0:
break;
case ARM_CP_NOP:
- return;
+ goto exit;
case ARM_CP_WFI:
if (isread) {
unallocated_encoding(s);
- return;
+ } else {
+ gen_update_pc(s, curr_insn_len(s));
+ s->base.is_jmp = DISAS_WFI;
}
- gen_update_pc(s, curr_insn_len(s));
- s->base.is_jmp = DISAS_WFI;
- return;
+ goto exit;
default:
g_assert_not_reached();
}
@@ -4843,9 +4843,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
if (ri->type & ARM_CP_CONST) {
tmp64 = tcg_constant_i64(ri->resetvalue);
} else if (ri->readfn) {
+ if (!tcg_ri) {
+ tcg_ri = gen_lookup_cp_reg(key);
+ }
tmp64 = tcg_temp_new_i64();
- gen_helper_get_cp_reg64(tmp64, cpu_env,
- tcg_constant_ptr(ri));
+ gen_helper_get_cp_reg64(tmp64, cpu_env, tcg_ri);
} else {
tmp64 = tcg_temp_new_i64();
tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset);
@@ -4862,8 +4864,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
if (ri->type & ARM_CP_CONST) {
tmp = tcg_constant_i32(ri->resetvalue);
} else if (ri->readfn) {
+ if (!tcg_ri) {
+ tcg_ri = gen_lookup_cp_reg(key);
+ }
tmp = tcg_temp_new_i32();
- gen_helper_get_cp_reg(tmp, cpu_env, tcg_constant_ptr(ri));
+ gen_helper_get_cp_reg(tmp, cpu_env, tcg_ri);
} else {
tmp = load_cpu_offset(ri->fieldoffset);
}
@@ -4881,7 +4886,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
/* Write */
if (ri->type & ARM_CP_CONST) {
/* If not forbidden by access permissions, treat as WI */
- return;
+ goto exit;
}
if (is64) {
@@ -4893,7 +4898,10 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
tcg_temp_free_i32(tmplo);
tcg_temp_free_i32(tmphi);
if (ri->writefn) {
- gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tmp64);
+ if (!tcg_ri) {
+ tcg_ri = gen_lookup_cp_reg(key);
+ }
+ gen_helper_set_cp_reg64(cpu_env, tcg_ri, tmp64);
} else {
tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset);
}
@@ -4901,7 +4909,10 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
} else {
TCGv_i32 tmp = load_reg(s, rt);
if (ri->writefn) {
- gen_helper_set_cp_reg(cpu_env, tcg_constant_ptr(ri), tmp);
+ if (!tcg_ri) {
+ tcg_ri = gen_lookup_cp_reg(key);
+ }
+ gen_helper_set_cp_reg(cpu_env, tcg_ri, tmp);
tcg_temp_free_i32(tmp);
} else {
store_cpu_offset(tmp, ri->fieldoffset, 4);
@@ -4929,6 +4940,11 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
if (need_exit_tb) {
gen_lookup_tb(s);
}
+
+ exit:
+ if (tcg_ri) {
+ tcg_temp_free_ptr(tcg_ri);
+ }
}
/* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */
Do not encode the pointer as a constant in the opcode stream. This pointer is specific to the cpu that first generated the translation, which runs into problems with both hot-pluggable cpus and user-only threads, as cpus are removed. Perform the lookup in either helper_access_check_cp_reg, or a new helper_lookup_cp_reg. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/helper.h | 11 +++++---- target/arm/translate.h | 7 ++++++ target/arm/op_helper.c | 27 ++++++++++++++------ target/arm/translate-a64.c | 49 ++++++++++++++++++++++--------------- target/arm/translate.c | 50 +++++++++++++++++++++++++------------- 5 files changed, 95 insertions(+), 49 deletions(-)