Commit 89d61955e7 for qemu.org

commit 89d61955e73bce56acea7982236037bf206d5f6b
Author: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
Date:   Mon Aug 24 08:58:13 2026 -0700

    target/hexagon: fix PC advancement for non-COF TB terminators

    Some packets end a translation block without a change-of-flow. These do
    not update the PC during commit, so gen_end_tb() leaves
    hex_gpr[HEX_REG_PC] pointing at the same packet and the block gets
    re-entered forever. Set PC explicitly to next_PC in that gen_end_tb()
    branch to fix execution of next blocks.

    Note that gen_start_packet() used to have a special case for
    tlblock/k0lock, setting ctx->next_PC to the packet's own address. This
    relies on the tlblock/k0lock helpers to properly advance the PC, which
    is never done (only env->next_PC is updated, but that never reaches
    hex_gpr[HEX_REG_PC]).  Drop the special case so these packets advance to
    the following packet like any other non-COF TB terminator.

    Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
    Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
    Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 06a8159d28..5463a07ec5 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -217,6 +217,12 @@ static void gen_end_tb(DisasContext *ctx)
         gen_goto_tb(ctx, 0, ctx->base.tb->pc, true);
         gen_set_label(skip);
         gen_goto_tb(ctx, 1, ctx->next_PC, false);
+    } else if (!ctx->pkt.pkt_has_cof) {
+        /*
+         * Packet with no deferred COF that still ends the TB. PC is
+         * not updated during commit, so set it explicitly to next_PC.
+         */
+         gen_goto_tb(ctx, 0, ctx->next_PC, true);
     } else {
         tcg_gen_lookup_and_goto_ptr();
     }
@@ -289,6 +295,7 @@ static bool check_for_attrib(Packet *pkt, int attrib)
     return false;
 }

+#ifndef CONFIG_USER_ONLY
 static bool check_for_opcode(Packet *pkt, uint16_t opcode)
 {
     for (int i = 0; i < pkt->num_insns; i++) {
@@ -298,6 +305,7 @@ static bool check_for_opcode(Packet *pkt, uint16_t opcode)
     }
     return false;
 }
+#endif

 static bool need_slot_cancelled(Packet *pkt)
 {
@@ -577,10 +585,7 @@ static void analyze_packet(DisasContext *ctx)
 static void gen_start_packet(DisasContext *ctx)
 {
     Packet *pkt = &ctx->pkt;
-    target_ulong next_PC = (check_for_opcode(pkt, Y2_k0lock) ||
-                            check_for_opcode(pkt, Y2_tlblock)) ?
-                               ctx->base.pc_next :
-                               ctx->base.pc_next + pkt->encod_pkt_size_in_bytes;
+    target_ulong next_PC = ctx->base.pc_next + pkt->encod_pkt_size_in_bytes;
     int i;

     /* Clear out the disassembly context */