From: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
To: Zephyr Li <fritchleybohrer@gmail.com>, qemu-devel@nongnu.org
Cc: qemu-riscv@nongnu.org, Palmer Dabbelt <palmer@dabbelt.com>,
Alistair Francis <alistair.francis@wdc.com>,
Weiwei Li <liwei1518@gmail.com>,
Liu Zhiwei <zhiwei_liu@linux.alibaba.com>,
Chao Liu <chao.liu@processmission.com>
Subject: Re: [PATCH] target/riscv: save ELP in MPELP for NMIE=0 exceptions
Date: Wed, 2 Sep 2026 08:31:25 -0300 [thread overview]
Message-ID: <2d8f63f8-721f-42a4-843e-3ec79de2c2ce@oss.qualcomm.com> (raw)
In-Reply-To: <20260902015704.101990-1-fritchleybohrer@gmail.com>
On 9/1/2026 10:57 PM, Zephyr Li wrote:
> When an exception occurs in M-mode while mnstatus.NMIE is clear,
> Smrnmi only changes the exception handler address. Trap state is still
> saved in the regular M-mode CSRs and the handler returns with MRET.
I believe it's worth adding the quote from the smrnmi spec. It's section 8.5,
"RNMI Operation":
"If the hart encounters an exception while executing in M-mode with the
mnstatus.NMIE bit clear, the exception is an RNMI exception. Trap state
is still saved in the regular M-mode CSRs and the handler returns with MRET."
>
> riscv_cpu_do_interrupt() instead saves ELP in mnstatus.MNPELP on this
> path. MRET restores ELP from mstatus.MPELP, so the expected landing-pad
> state is lost.
>
> Always save ELP in mstatus.MPELP for M-mode exceptions. Keep MNPELP for
> the actual RNMI interrupt path, which returns with MNRET.
>
> Add a TCG test that checks ELP preservation across an NMIE=0 M-mode
> exception and MRET.
>
> Fixes: 0266fd8b56a4 ("target/riscv: Add Zicfilp support for Smrnmi")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4223
> Signed-off-by: Zephyr Li <fritchleybohrer@gmail.com>
> ---
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> target/riscv/tcg/cpu_helper.c | 18 +---
> tests/tcg/riscv64/Makefile.softmmu-target | 8 ++
> tests/tcg/riscv64/test-zicfilp-smrnmi.S | 117 ++++++++++++++++++++++
> 3 files changed, 127 insertions(+), 16 deletions(-)
> create mode 100644 tests/tcg/riscv64/test-zicfilp-smrnmi.S
>
> diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c
> index 07d9222652..a0d79b33a5 100644
> --- a/target/riscv/tcg/cpu_helper.c
> +++ b/target/riscv/tcg/cpu_helper.c
> @@ -2264,23 +2264,9 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>
> src = env->sepc;
> } else {
> - /*
> - * If the hart encounters an exception while executing in M-mode
> - * with the mnstatus.NMIE bit clear, the exception is an RNMI exception.
> - */
> - nnmi_excep = cpu->cfg.ext_smrnmi &&
> - !get_field(env->mnstatus, MNSTATUS_NMIE) &&
> - !async;
> -
> - /* handle the trap in M-mode */
> - /* save elp status */
> + /* Save ELP for MRET. */
> if (cpu_get_fcfien(env)) {
> - if (nnmi_excep) {
> - env->mnstatus = set_field(env->mnstatus, MNSTATUS_MNPELP,
> - env->elp);
> - } else {
> - env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
> - }
> + env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
> }
>
> if (riscv_has_ext(env, RVH)) {
> diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
> index 6a219c306c..8522c3fe6f 100644
> --- a/tests/tcg/riscv64/Makefile.softmmu-target
> +++ b/tests/tcg/riscv64/Makefile.softmmu-target
> @@ -45,6 +45,14 @@ comma:= ,
> run-test-crc32: test-crc32
> $(call run-test, $<, $(QEMU) -cpu rv64$(comma)xlrbr=true $(QEMU_OPTS)$<)
>
> +EXTRA_RUNS += run-test-zicfilp-smrnmi
> +run-test-zicfilp-smrnmi: test-zicfilp-smrnmi
> + $(call run-test, $<, \
> + $(QEMU) \
> + -cpu rv64$(comma)zicsr=true$(comma)zicfilp=true$(comma)smrnmi=true \
> + -global rv64-riscv-cpu.rnmi-exception-vector=0x80000100 \
> + $(QEMU_OPTS)$<)
> +
> # Zicclsm: misaligned load/store support. Assemble one source twice: the
> # default build expects every misaligned access to succeed (zicclsm=true),
> # the -DZICCLSM_DISABLED build expects every one to trap (zicclsm=false).
> diff --git a/tests/tcg/riscv64/test-zicfilp-smrnmi.S b/tests/tcg/riscv64/test-zicfilp-smrnmi.S
> new file mode 100644
> index 0000000000..b5965bf705
> --- /dev/null
> +++ b/tests/tcg/riscv64/test-zicfilp-smrnmi.S
> @@ -0,0 +1,117 @@
> +/*
> + * Test that an M-mode exception taken with mnstatus.NMIE clear saves ELP in
> + * mstatus.MPELP, so that it is restored by MRET. MNPELP is reserved for the
> + * actual RNMI path, which returns with MNRET.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> + .option norvc
> +
> + .equ CSR_MNSTATUS, 0x744
> + .equ CSR_MSECCFG, 0x747
> + .equ MNSTATUS_NMIE, 1 << 3
> + .equ MNSTATUS_MNPELP, 1 << 9
> + .equ MSECCFG_MLPE, 1 << 10
> + .equ MSTATUS_MPELP, 1 << 41
> + .equ EXCP_INST_ACCESS_FAULT, 1
> + .equ EXCP_SW_CHECK, 18
> + .equ SW_CHECK_FCFI_TVAL, 2
> +
> + .text
> + .global _start
> +_start:
> + /* Verify that NMIE is clear before exercising the exception path. */
> + csrr t0, CSR_MNSTATUS
> + andi t0, t0, MNSTATUS_NMIE
> + bnez t0, fail_nmie
> +
> + /* Enable landing-pad checks in M-mode, then start a new TB. */
> + li t0, MSECCFG_MLPE
> + csrs CSR_MSECCFG, t0
> + j tracked_jump
> +
> +tracked_jump:
> + /* Make a Zicfilp-tracked indirect jump to an address that faults. */
> + li t1, 0
> + jalr zero, 0(t1)
> +
> + /*
> + * The instruction access fault should have redirected to the handler.
> + */
> + li a0, 1
> + j _exit
> +
> +fail_nmie:
> + li a0, 6
> + j _exit
> +
> + /* Must match rnmi-exception-vector in Makefile.softmmu-target. */
> + .org 0x100
> +rnmi_exception:
> + csrr t0, mcause
> + li t1, EXCP_INST_ACCESS_FAULT
> + beq t0, t1, handle_fetch_fault
> + li t1, EXCP_SW_CHECK
> + beq t0, t1, handle_sw_check
> +
> + li a0, 4
> + j _exit
> +
> +handle_fetch_fault:
> + /* This is an M-mode exception and will return with MRET. */
> + csrr t0, mstatus
> + li t1, MSTATUS_MPELP
> + and t0, t0, t1
> + beqz t0, fail_mpelp
> +
> + csrr t0, CSR_MNSTATUS
> + andi t0, t0, MNSTATUS_MNPELP
> + bnez t0, fail_mnpelp
> +
> + lla t0, resume_non_lpad
> + csrw mepc, t0
> + mret
> +
> +resume_non_lpad:
> + /* MRET must restore ELP, so this instruction must not retire. */
> + li a0, 1
> + j _exit
> +
> +handle_sw_check:
> + csrr t0, mtval
> + li t1, SW_CHECK_FCFI_TVAL
> + bne t0, t1, fail_tval
> +
> + li a0, 0
> + j _exit
> +
> +fail_mpelp:
> + li a0, 2
> + j _exit
> +
> +fail_mnpelp:
> + li a0, 3
> + j _exit
> +
> +fail_tval:
> + li a0, 5
> +
> +_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 .
> +
> + .data
> + .balign 16
> +semiargs:
> + .space 16
prev parent reply other threads:[~2026-09-02 11:31 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 1:57 [PATCH] target/riscv: save ELP in MPELP for NMIE=0 exceptions Zephyr Li
2026-09-02 11:31 ` Daniel Henrique Barboza [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2d8f63f8-721f-42a4-843e-3ec79de2c2ce@oss.qualcomm.com \
--to=daniel.barboza@oss.qualcomm.com \
--cc=alistair.francis@wdc.com \
--cc=chao.liu@processmission.com \
--cc=fritchleybohrer@gmail.com \
--cc=liwei1518@gmail.com \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.