aboutsummaryrefslogtreecommitdiff
path: root/target/arm/translate.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2023-01-06 11:44:51 -0800
committerPeter Maydell <peter.maydell@linaro.org>2023-01-23 13:32:38 +0000
commit3b07a936d3bfe97b07ddffcfbb532985a88033dd (patch)
tree11bf566db142db5e6c3ab8e7a333f21ff252ba73 /target/arm/translate.c
parent0371fa90a1b65b1536b3ff7ba583e4119c363eea (diff)
target/arm: Look up ARMCPRegInfo at runtimepull-target-arm-20230123
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. It's also a potential correctness issue in the theoretical case of a slightly-heterogenous system, because if CPU 0 generates a TB and then CPU 1 executes it, CPU 1 will end up using CPU 0's hash table, which might have a wrong set of registers in it. (All our current systems are either completely homogenous, M-profile, or have CPUs sufficiently different that they wouldn't be sharing TBs anyway because the differences would show up in the TB flags, so the correctness issue is only theoretical, not practical.) 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> Message-id: 20230106194451.1213153-3-richard.henderson@linaro.org [PMM: added note in commit message about correctness issue] Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/arm/translate.c')
-rw-r--r--target/arm/translate.c50
1 files changed, 33 insertions, 17 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 40f9f07ea3..365e02fb0b 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -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) */