Commit d372cbc1c8 for qemu.org
commit d372cbc1c824c4346d1b822928d888fc04952af3
Author: Marco Liebel <marco.liebel@oss.qualcomm.com>
Date: Mon Nov 9 15:21:41 2026 -0800
target/hexagon: serialize TLB invalidation and IMASK access
Hold the shared TLB mutex during ASID invalidation so it cannot
overwrite a concurrent entry replacement.
Route local IMASK reads and writes through BQL-protected helpers
to serialize them with cross-thread interrupt assignment. Apply
the pre-V81 writable-bit mask under the same lock.
Signed-off-by: Marco Liebel <marco.liebel@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
diff --git a/hw/hexagon/hexagon_tlb.c b/hw/hexagon/hexagon_tlb.c
index 3e72026d62..07406cea35 100644
--- a/hw/hexagon/hexagon_tlb.c
+++ b/hw/hexagon/hexagon_tlb.c
@@ -325,6 +325,7 @@ uint32_t hexagon_tlb_invalidate_asid(HexagonTLBState *tlb, uint32_t asid)
{
uint32_t invalidated = 0;
+ QEMU_LOCK_GUARD(&tlb->lock);
for (uint32_t i = 0; i < tlb->num_entries; i++) {
uint64_t entry = tlb->entries[i];
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index addb5d23d9..52615628e3 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -302,13 +302,11 @@ static void gen_log_sreg_write(DisasContext *ctx, int rnum, TCGv_i32 val)
if (rnum == HEX_SREG_MODECTL || rnum == HEX_SREG_SYSCFG) {
translator_io_start(&ctx->base);
}
- if (rnum == HEX_SREG_IMASK &&
- ctx->hex_def->hex_version < HEX_VER_V81) {
- reg_mask = 0xffff0000;
- }
-
if (reg_mask != IMMUTABLE) {
- if (rnum < HEX_SREG_GLB_START) {
+ if (rnum == HEX_SREG_IMASK) {
+ /* Commit through a helper to serialize with iassignw/setimask. */
+ tcg_gen_mov_i32(ctx->t_sreg_new_value[rnum], val);
+ } else if (rnum < HEX_SREG_GLB_START) {
gen_masked_reg_write(val, hex_t_sreg[rnum], reg_mask);
if (ctx->need_commit || rnum == HEX_SREG_SSR ||
rnum == HEX_SREG_CCR) {
@@ -343,7 +341,8 @@ static void gen_read_sreg(DisasContext *ctx, TCGv_i32 dst, int reg_num)
reg_num == HEX_SREG_PCYCLELO || reg_num == HEX_SREG_PCYCLEHI) {
translator_io_start(&ctx->base);
}
- if (reg_num >= HEX_SREG_GLB_START || reg_num == HEX_SREG_BADVA) {
+ if (reg_num >= HEX_SREG_GLB_START || reg_num == HEX_SREG_BADVA ||
+ reg_num == HEX_SREG_IMASK) {
gen_helper_sreg_read(dst, tcg_env, tcg_constant_i32(reg_num));
} else {
tcg_gen_mov_i32(dst, hex_t_sreg[reg_num]);
@@ -356,7 +355,9 @@ static void gen_read_sreg_pair(DisasContext *ctx, TCGv_i64 dst, int reg_num)
if (reg_num == HEX_SREG_TIMERLO || reg_num == HEX_SREG_PCYCLELO) {
translator_io_start(&ctx->base);
}
- if (reg_num < HEX_SREG_GLB_START) {
+ if (reg_num == HEX_SREG_IMASK) {
+ gen_helper_sreg_read_pair(dst, tcg_env, tcg_constant_i32(reg_num));
+ } else if (reg_num < HEX_SREG_GLB_START) {
if (reg_num + 1 == HEX_SREG_BADVA) {
TCGv_i32 badva = tcg_temp_new_i32();
gen_helper_sreg_read(badva, tcg_env,
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 0a16778e5e..71b27ef07f 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1994,6 +1994,10 @@ void HELPER(sreg_write_masked)(CPUHexagonState *env, uint32_t reg, uint32_t val)
{
BQL_LOCK_GUARD();
if (reg < HEX_SREG_GLB_START) {
+ if (reg == HEX_SREG_IMASK &&
+ env_archcpu(env)->cfg.hex_def->hex_version < HEX_VER_V81) {
+ val = deposit32(env->t_sreg[reg], 0, 16, val);
+ }
env->t_sreg[reg] = val;
} else {
HexagonCPU *cpu = env_archcpu(env);
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 8ab28d40d3..ec1d79e31f 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -804,8 +804,13 @@ static void gen_start_packet(DisasContext *ctx)
int reg_num = ctx->sreg_log[i];
if (reg_num < HEX_SREG_GLB_START) {
ctx->t_sreg_new_value[reg_num] = tcg_temp_new();
- tcg_gen_mov_tl(ctx->t_sreg_new_value[reg_num],
- hex_t_sreg[reg_num]);
+ if (reg_num == HEX_SREG_IMASK) {
+ gen_helper_sreg_read(ctx->t_sreg_new_value[reg_num], tcg_env,
+ tcg_constant_i32(reg_num));
+ } else {
+ tcg_gen_mov_tl(ctx->t_sreg_new_value[reg_num],
+ hex_t_sreg[reg_num]);
+ }
}
}
for (i = 0; i < NUM_GREGS; i++) {
@@ -1071,8 +1076,11 @@ static void gen_sreg_writes(DisasContext *ctx)
old_reg);
/* A CCR write can change context, so end the TB. */
ctx->base.is_jmp = DISAS_NORETURN;
+ } else if (reg_num == HEX_SREG_IMASK) {
+ gen_helper_sreg_write_masked(tcg_env, tcg_constant_i32(reg_num),
+ ctx->t_sreg_new_value[reg_num]);
+ gen_helper_pending_interrupt(tcg_env);
} else if ((reg_num == HEX_SREG_STID) ||
- (reg_num == HEX_SREG_IMASK) ||
(reg_num == HEX_SREG_IPENDAD) ||
(reg_num == HEX_SREG_IPEND) ||
(reg_num == HEX_SREG_IAD)) {
@@ -1715,7 +1723,7 @@ void hexagon_translate_init(void)
hexagon_gregnames[i]);
}
for (i = 0; i < NUM_SREGS; i++) {
- if (i < HEX_SREG_GLB_START) {
+ if (i < HEX_SREG_GLB_START && i != HEX_SREG_IMASK) {
hex_t_sreg[i] = tcg_global_mem_new_i32(tcg_env,
offsetof(CPUHexagonState, t_sreg[i]),
hexagon_sregnames[i]);