Got it, thanks!

On Thu, Sep 10, 2026 at 4:00 AM Daniel Henrique Barboza <
[email protected]> wrote:

>
>
> On 9/7/2026 11:27 PM, Zephyr Li wrote:
> > helper_wfi() never returns to translated code: it either raises an
> > exception or exits the CPU loop after marking the CPU as halted. However,
> > trans_wfi() leaves the translation state as DISAS_NEXT, so instructions
> > following WFI can be included in the same TB.
> >
> > With icount enabled, this makes the following instruction part of the
> TB's
> > instruction count when WFI exits, causing minstret to be incremented once
> > too many. Set DISAS_NORETURN after emitting the helper.
> >
> > Add a TCG test for both reported cases: WFI waking for a locally enabled
> > pending interrupt with mstatus.MIE clear, and WFI taking a timer
> interrupt.
> >
> > Fixes: 55c2a12cbcd3 ("RISC-V TCG Code Generation")
> > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4230
> > Signed-off-by: Zephyr Li <[email protected]>
> > ---
>
> Code LGTM.  We just need to use the meson stuff for the new
> test-minstret-wfi.S
> test.  Otherwise 'check-tcg' won't execute it.
>
>
> Thanks,
> Daniel
>
> >   .../tcg/insn_trans/trans_privileged.c.inc     |   1 +
> >   tests/tcg/riscv64/Makefile.softmmu-target     |   4 +
> >   tests/tcg/riscv64/test-minstret-wfi.S         | 100 ++++++++++++++++++
> >   3 files changed, 105 insertions(+)
> >   create mode 100644 tests/tcg/riscv64/test-minstret-wfi.S
> >
> > diff --git a/target/riscv/tcg/insn_trans/trans_privileged.c.inc
> b/target/riscv/tcg/insn_trans/trans_privileged.c.inc
> > index a8eaccef67..ebbbb01179 100644
> > --- a/target/riscv/tcg/insn_trans/trans_privileged.c.inc
> > +++ b/target/riscv/tcg/insn_trans/trans_privileged.c.inc
> > @@ -145,6 +145,7 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
> >       decode_save_opc(ctx, 0);
> >       gen_update_pc(ctx, ctx->cur_insn_len);
> >       gen_helper_wfi(tcg_env);
> > +    ctx->base.is_jmp = DISAS_NORETURN;
> >       return true;
> >   #else
> >       return false;
> > diff --git a/tests/tcg/riscv64/Makefile.softmmu-target
> b/tests/tcg/riscv64/Makefile.softmmu-target
> > index 6a219c306c..96a3ab32c9 100644
> > --- a/tests/tcg/riscv64/Makefile.softmmu-target
> > +++ b/tests/tcg/riscv64/Makefile.softmmu-target
> > @@ -28,6 +28,10 @@ EXTRA_RUNS += run-test-minstret-ecall
> >   run-test-minstret-ecall: test-minstret-ecall
> >       $(call run-test, $<, $(QEMU) -icount shift=1 $(QEMU_OPTS)$<)
> >
> > +EXTRA_RUNS += run-test-minstret-wfi
> > +run-test-minstret-wfi: test-minstret-wfi
> > +     $(call run-test, $<, $(QEMU) -icount shift=1 $(QEMU_OPTS)$<)
> > +
> >   EXTRA_RUNS += run-plugin-doubletrap
> >   run-plugin-doubletrap: doubletrap
> >       $(call run-test, $<, \
> > diff --git a/tests/tcg/riscv64/test-minstret-wfi.S
> b/tests/tcg/riscv64/test-minstret-wfi.S
> > new file mode 100644
> > index 0000000000..0fd0158d5b
> > --- /dev/null
> > +++ b/tests/tcg/riscv64/test-minstret-wfi.S
> > @@ -0,0 +1,100 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +
> > +     .option norvc
> > +
> > +     .text
> > +     .global _start
> > +_start:
> > +     lla     t0, trap
> > +     csrw    mtvec, t0
> > +     li      s3, 0
> > +
> > +     /*
> > +      * A pending, locally enabled interrupt wakes WFI even with MIE
> > +      * clear.
> > +      */
> > +     li      t0, 0x8         /* MIE_MSIE */
> > +     csrw    mie, t0
> > +     csrci   mstatus, 0x8    /* MSTATUS_MIE */
> > +     li      t0, 0x2000000   /* MSIP0 */
> > +     li      t1, 1
> > +     sw      t1, 0(t0)
> > +
> > +     /*
> > +      * The first CSR read and WFI retire before the second read
> obtains s1,
> > +      * so the expected difference is two.
> > +      */
> > +     csrr    s0, minstret
> > +     wfi
> > +     csrr    s1, minstret
> > +     sub     s1, s1, s0
> > +     li      t1, 2
> > +     beq     s1, t1, 1f
> > +     ori     s3, s3, 1
> > +1:
> > +
> > +     /* Clear the software interrupt before testing the trap path. */
> > +     sw      zero, 0(t0)
> > +     csrw    mie, zero
> > +
> > +     /* Schedule a timer interrupt far enough ahead to reach WFI first.
> */
> > +     li      t0, 0x200bff8   /* MTIME */
> > +     ld      t1, 0(t0)
> > +     addi    t1, t1, 100
> > +     li      t0, 0x2004000   /* MTIMECMP0 */
> > +     sd      t1, 0(t0)
> > +     li      t0, 0x80                /* MIE_MTIE */
> > +     csrw    mie, t0
> > +     csrsi   mstatus, 0x8    /* MSTATUS_MIE */
> > +
> > +     /*
> > +      * The first CSR read and WFI retire before the trap handler
> obtains s1,
> > +      * so the expected difference is again two.
> > +      */
> > +     li      s2, 1
> > +     csrr    s0, minstret
> > +     wfi
> > +     beqz    s2, 1f
> > +     ori     s3, s3, 2
> > +1:
> > +     bnez    s3, fail
> > +     li      a0, 0
> > +     j       _exit
> > +
> > +fail:
> > +     mv      a0, s3
> > +
> > +_exit:
> > +     lla     a1, semiargs
> > +     li      t0, 0x20026     /* ADP_Stopped_ApplicationExit */
> > +     sd      t0, 0(a1)
> > +     sd      a0, 8(a1)
> > +     li      a0, 0x20        /* TARGET_SYS_EXIT_EXTENDED */
> > +
> > +     /* Semihosting call sequence */
> > +     .balign 16
> > +     slli    zero, zero, 0x1f
> > +     ebreak
> > +     srai    zero, zero, 0x7
> > +     j       .
> > +
> > +     .balign 4
> > +trap:
> > +     /* Read minstret before retiring an instruction in the handler. */
> > +     csrr    s1, minstret
> > +     sub     s1, s1, s0
> > +     addi    s1, s1, -2
> > +     snez    s2, s1
> > +
> > +     /* Disable the timer interrupt before returning past WFI. */
> > +     li      t0, 0x2004000   /* MTIMECMP0 */
> > +     li      t1, -1
> > +     sd      t1, 0(t0)
> > +     li      t0, 0x80                /* MIE_MTIE */
> > +     csrc    mie, t0
> > +     mret
> > +
> > +     .data
> > +     .balign 16
> > +semiargs:
> > +     .space  16
>
>

Reply via email to