From: Will Deacon <will@kernel.org>
To: kvmarm@lists.linux.dev
Cc: mark.rutland@arm.com, linux-arm-kernel@lists.infradead.org,
Will Deacon <will@kernel.org>, Marc Zyngier <maz@kernel.org>,
Oliver Upton <oupton@kernel.org>,
James Clark <james.clark@linaro.org>, Leo Yan <leo.yan@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Fuad Tabba <tabba@google.com>
Subject: [PATCH] KVM: arm64: Disable TRBE Trace Buffer Unit when running in guest context
Date: Mon, 16 Feb 2026 13:09:59 +0000 [thread overview]
Message-ID: <20260216130959.19317-1-will@kernel.org> (raw)
The nVHE world-switch code relies on zeroing TRFCR_EL1 to disable trace
generation in guest context when self-hosted TRBE is in use by the host.
Per D3.2.1 ("Controls to prohibit trace at Exception levels"), clearing
TRFCR_EL1 means that trace generation is prohibited at EL1 and EL0 but
per R_YCHKJ the Trace Buffer Unit will still be enabled if
TRBLIMITR_EL1.E is set. R_SJFRQ goes on to state that, when enabled, the
Trace Buffer Unit can perform address translation for the "owning
exception level" even when it is out of context.
Consequently, we can end up in a state where TRBE performs speculative
page-table walks for a host VA/IPA in guest/hypervisor context depending
on the value of MDCR_EL2.E2TB, which changes over world-switch. The
result appears to be a heady mixture of data corruption and hardware
lockups.
Extend the TRBE world-switch code to clear TRBLIMITR_EL1.E after
draining the buffer, restoring the register on return to the host.
Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oupton@kernel.org>
Cc: James Clark <james.clark@linaro.org>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Fixes: a1319260bf62 ("arm64: KVM: Enable access to TRBE support for host")
Signed-off-by: Will Deacon <will@kernel.org>
---
NOTE: This is *untested* as I don't have a TRBE-capable device that can
run upstream but I noticed this by inspection when triaging occasional
hardware lockups on systems using a 6.12-based kernel with TRBE running
at the same time as a vCPU is loaded. This code has changed quite a bit
over time, so stable backports are not entirely straightforward.
Hopefully James/Leo/Suzuki can help us test if folks agree with the
general approach taken here.
arch/arm64/include/asm/kvm_host.h | 1 +
arch/arm64/kvm/hyp/nvhe/debug-sr.c | 36 ++++++++++++++++++++++--------
2 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c7883..a932cf043b83 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -746,6 +746,7 @@ struct kvm_host_data {
u64 pmscr_el1;
/* Self-hosted trace */
u64 trfcr_el1;
+ u64 trblimitr_el1;
/* Values of trap registers for the host before guest entry. */
u64 mdcr_el2;
u64 brbcr_el1;
diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
index 2a1c0f49792b..fd389a26bc59 100644
--- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c
@@ -57,12 +57,27 @@ static void __trace_do_switch(u64 *saved_trfcr, u64 new_trfcr)
write_sysreg_el1(new_trfcr, SYS_TRFCR);
}
-static bool __trace_needs_drain(void)
+static void __trace_drain_and_disable(void)
{
- if (is_protected_kvm_enabled() && host_data_test_flag(HAS_TRBE))
- return read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_EL1_E;
+ u64 *trblimitr_el1 = host_data_ptr(host_debug_state.trblimitr_el1);
- return host_data_test_flag(TRBE_ENABLED);
+ *trblimitr_el1 = 0;
+
+ if (is_protected_kvm_enabled()) {
+ if (!host_data_test_flag(HAS_TRBE))
+ return;
+ } else {
+ if (!host_data_test_flag(TRBE_ENABLED))
+ return;
+ }
+
+ *trblimitr_el1 = read_sysreg_s(SYS_TRBLIMITR_EL1);
+ if (*trblimitr_el1 & TRBLIMITR_EL1_E) {
+ isb();
+ tsb_csync();
+ write_sysreg_s(0, SYS_TRBLIMITR_EL1);
+ isb();
+ }
}
static bool __trace_needs_switch(void)
@@ -79,15 +94,18 @@ static void __trace_switch_to_guest(void)
__trace_do_switch(host_data_ptr(host_debug_state.trfcr_el1),
*host_data_ptr(trfcr_while_in_guest));
-
- if (__trace_needs_drain()) {
- isb();
- tsb_csync();
- }
+ __trace_drain_and_disable();
}
static void __trace_switch_to_host(void)
{
+ u64 trblimitr_el1 = *host_data_ptr(host_debug_state.trblimitr_el1);
+
+ if (trblimitr_el1 & TRBLIMITR_EL1_E) {
+ write_sysreg_s(trblimitr_el1, SYS_TRBLIMITR_EL1);
+ isb();
+ }
+
__trace_do_switch(host_data_ptr(trfcr_while_in_guest),
*host_data_ptr(host_debug_state.trfcr_el1));
}
--
2.53.0.273.g2a3d683680-goog
next reply other threads:[~2026-02-16 13:11 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-16 13:09 Will Deacon [this message]
2026-02-16 14:29 ` [PATCH] KVM: arm64: Disable TRBE Trace Buffer Unit when running in guest context Marc Zyngier
2026-02-16 15:05 ` James Clark
2026-02-16 15:51 ` Marc Zyngier
2026-02-16 16:10 ` James Clark
2026-02-16 16:49 ` Marc Zyngier
2026-02-20 11:42 ` James Clark
2026-02-24 11:19 ` Marc Zyngier
2026-02-20 15:48 ` Leo Yan
2026-02-24 11:22 ` Marc Zyngier
2026-02-16 18:14 ` Will Deacon
2026-02-17 14:19 ` Leo Yan
2026-02-17 14:52 ` Will Deacon
2026-02-17 19:01 ` Leo Yan
2026-02-19 13:54 ` Will Deacon
2026-02-19 18:58 ` Leo Yan
2026-02-19 19:06 ` Leo Yan
2026-02-25 12:09 ` Leo Yan
2026-02-27 18:07 ` Will Deacon
2026-03-03 10:36 ` Leo Yan
2026-03-03 10:47 ` Suzuki K Poulose
2026-02-16 15:53 ` Alexandru Elisei
2026-02-16 17:10 ` Will Deacon
2026-02-17 12:13 ` Will Deacon
2026-02-16 17:32 ` Will Deacon
2026-02-17 12:20 ` James Clark
2026-02-17 12:26 ` Will Deacon
2026-02-17 13:58 ` James Clark
2026-02-16 15:13 ` James Clark
2026-02-16 17:05 ` Will Deacon
2026-02-17 9:18 ` James Clark
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=20260216130959.19317-1-will@kernel.org \
--to=will@kernel.org \
--cc=james.clark@linaro.org \
--cc=kvmarm@lists.linux.dev \
--cc=leo.yan@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=tabba@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox