@@ -35,6 +35,9 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \
file://qemu-guest-agent.init \
file://qemu-guest-agent.udev \
file://0001-ui-sdl2.c-force-disable-SDL_HINT_VIDEO_X11_FORCE_EGL.patch \
+ file://0001-target-riscv-extract-sfence_vma_allowed-from-helper_.patch \
+ file://0002-target-riscv-add-helper_tlb_flush_page.patch \
+ file://0003-target-riscv-use-a-targeted-TLB-page-flush-for-sfenc.patch \
"
# file index at download.qemu.org isn't reliable: https://gitlab.com/qemu-project/qemu-web/-/issues/9
UPSTREAM_CHECK_URI = "https://www.qemu.org"
new file mode 100644
@@ -0,0 +1,56 @@
+From 8507fd6795753697f557d11e144568f1bf8a00cb Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Mon, 24 Aug 2026 17:54:21 +0000
+Subject: [PATCH 1/3] target/riscv: extract sfence_vma_allowed() from
+ helper_tlb_flush()
+
+Create a new function to encapsulate the privilege/hypervisor checks
+performed inside helper_tlb_flush(). The idea is to pass GETPC() as an
+argument directly to it inside the helper_tlb_flush() function.
+
+Upstream-Status: Submitted [https://lists.gnu.org/archive/html/qemu-devel/2026-08/msg08496.html]
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ target/riscv/tcg/op_helper.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c
+index 3e94005d2b..8039df2b48 100644
+--- a/target/riscv/tcg/op_helper.c
++++ b/target/riscv/tcg/op_helper.c
+@@ -588,18 +588,25 @@ void helper_wrs_nto(CPURISCVState *env)
+ }
+ }
+
+-void helper_tlb_flush(CPURISCVState *env)
++static bool sfence_vma_allowed(CPURISCVState *env, uintptr_t ra)
+ {
+- CPUState *cs = env_cpu(env);
+ if (!env->virt_enabled &&
+ (env->priv == PRV_U ||
+ (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)))) {
+- riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
++ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra);
++ return false;
+ } else if (env->virt_enabled &&
+ (env->priv == PRV_U || get_field(env->hstatus, HSTATUS_VTVM))) {
+- riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
+- } else {
+- tlb_flush(cs);
++ riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, ra);
++ return false;
++ }
++ return true;
++}
++
++void helper_tlb_flush(CPURISCVState *env)
++{
++ if (sfence_vma_allowed(env, GETPC())) {
++ tlb_flush(env_cpu(env));
+ }
+ }
+
+--
+2.55.0
+
new file mode 100644
@@ -0,0 +1,50 @@
+From eb8773847363989d9396492a3c9bc517ca04959f Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Mon, 24 Aug 2026 17:54:45 +0000
+Subject: [PATCH 2/3] target/riscv: add helper_tlb_flush_page()
+
+Add a page-level counterpart to helper_tlb_flush(), and condition its
+internal call to tlb_flush_page() on return value from the new
+sfence_vma_allowed() function.
+
+Upstream-Status: Submitted [https://lists.gnu.org/archive/html/qemu-devel/2026-08/msg08496.html]
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ target/riscv/helper.h | 1 +
+ target/riscv/tcg/op_helper.c | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/target/riscv/helper.h b/target/riscv/helper.h
+index 4fc2d3a155..652f85a5c7 100644
+--- a/target/riscv/helper.h
++++ b/target/riscv/helper.h
+@@ -137,6 +137,7 @@ DEF_HELPER_1(ctr_clear, void, env)
+ DEF_HELPER_1(wfi, void, env)
+ DEF_HELPER_1(wrs_nto, void, env)
+ DEF_HELPER_1(tlb_flush, void, env)
++DEF_HELPER_2(tlb_flush_page, void, env, tl)
+ DEF_HELPER_1(tlb_flush_all, void, env)
+ DEF_HELPER_4(ctr_add_entry, void, env, tl, tl, tl)
+ /* Native Debug */
+diff --git a/target/riscv/tcg/op_helper.c b/target/riscv/tcg/op_helper.c
+index 8039df2b48..723a45d181 100644
+--- a/target/riscv/tcg/op_helper.c
++++ b/target/riscv/tcg/op_helper.c
+@@ -610,6 +610,13 @@ void helper_tlb_flush(CPURISCVState *env)
+ }
+ }
+
++void helper_tlb_flush_page(CPURISCVState *env, target_ulong addr)
++{
++ if (sfence_vma_allowed(env, GETPC())) {
++ tlb_flush_page(env_cpu(env), addr);
++ }
++}
++
+ void helper_tlb_flush_all(CPURISCVState *env)
+ {
+ CPUState *cs = env_cpu(env);
+--
+2.55.0
+
new file mode 100644
@@ -0,0 +1,47 @@
+From 858d6d9a587e4ed44f92e017375c5265bc40934b Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Mon, 24 Aug 2026 17:55:00 +0000
+Subject: [PATCH 3/3] target/riscv: use a targeted TLB page flush for
+ sfence.vma with a vaddr operand
+
+sfence.vma unconditionally called helper_tlb_flush(), regardless of the
+rs1 (vaddr) and rs2 (asid) operands, forcing a page-table walk on the
+next access. Use helper_tlb_flush_page() whenever rs1 != 0, falling back
+to the existing full flush for rs1 == 0. This makes RISC-V behaviour
+more similar to ARM's equivalent (tlbi_aa64_vae1_write), which already
+does tlb_flush_page_by_mmuidx() instead of a full flush.
+
+Pass get_address(ctx, a->rs1, 0) to gen_helper_tlb_flush_page() rather
+than get_gpr(), so that the address being passed matches the current
+addr_xl width regardless of '-cpu' input. Otherwise, the raw register
+value can carry garbage above that width and never match the address the
+TLB entry was actually filled under, so the flush silently misses and a
+stale mapping survives.
+
+Upstream-Status: Submitted [https://lists.gnu.org/archive/html/qemu-devel/2026-08/msg08496.html]
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ target/riscv/tcg/insn_trans/trans_privileged.c.inc | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/target/riscv/tcg/insn_trans/trans_privileged.c.inc b/target/riscv/tcg/insn_trans/trans_privileged.c.inc
+index a8eaccef67..8655fa332e 100644
+--- a/target/riscv/tcg/insn_trans/trans_privileged.c.inc
++++ b/target/riscv/tcg/insn_trans/trans_privileged.c.inc
+@@ -155,7 +155,11 @@ static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
+ {
+ #ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx, 0);
+- gen_helper_tlb_flush(tcg_env);
++ if (a->rs1 == 0) {
++ gen_helper_tlb_flush(tcg_env);
++ } else {
++ gen_helper_tlb_flush_page(tcg_env, get_address(ctx, a->rs1, 0));
++ }
+ return true;
+ #endif
+ return false;
+--
+2.55.0
+
The QEMU TCG framework currently does an unconditional flush on TLBs regardless of vaddr and asid values, adding a lot of overhead to RISC-V runtimes. Backport some patches from the qemu-devel mailing list which improve this part of the TCG logic. For more info: https://lists.gnu.org/archive/html/qemu-devel/2026-08/msg08496.html Here is an example of the kind of runtime speed-up these changes help with (taken from the upstream link): |============================================================================ |Testsuite summary for GNU coreutils 9.11 |============================================================================ |# TOTAL: 733 |# PASS: 561 |# SKIP: 172 |# XFAIL: 0 |# FAIL: 0 |# XPASS: 0 |# ERROR: 0 |============================================================================ |make[1]: Leaving directory '/usr/lib/coreutils/ptest' |DURATION: 1049 |END: /usr/lib/coreutils/ptest |2026-08-31T17:23 |STOP: ptest-runner |TOTAL: 1 FAIL: 0 versus: |============================================================================ |Testsuite summary for GNU coreutils 9.11 |============================================================================ |# TOTAL: 733 |# PASS: 561 |# SKIP: 172 |# XFAIL: 0 |# FAIL: 0 |# XPASS: 0 |# ERROR: 0 |============================================================================ |make[1]: Leaving directory '/usr/lib/coreutils/ptest' |DURATION: 646 |END: /usr/lib/coreutils/ptest |2026-08-31T16:10 |STOP: ptest-runner |TOTAL: 1 FAIL: 0 |root@qemuriscv64:~# Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com> --- meta/recipes-devtools/qemu/qemu.inc | 3 + ...ract-sfence_vma_allowed-from-helper_.patch | 56 +++++++++++++++++++ ...rget-riscv-add-helper_tlb_flush_page.patch | 50 +++++++++++++++++ ...-a-targeted-TLB-page-flush-for-sfenc.patch | 47 ++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 meta/recipes-devtools/qemu/qemu/0001-target-riscv-extract-sfence_vma_allowed-from-helper_.patch create mode 100644 meta/recipes-devtools/qemu/qemu/0002-target-riscv-add-helper_tlb_flush_page.patch create mode 100644 meta/recipes-devtools/qemu/qemu/0003-target-riscv-use-a-targeted-TLB-page-flush-for-sfenc.patch