* [PATCH] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
@ 2026-09-03 16:08 Fuad Tabba
2026-09-04 9:58 ` Yao Yuan
0 siblings, 1 reply; 4+ messages in thread
From: Fuad Tabba @ 2026-09-03 16:08 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon
Cc: James Morse, Ben Horgan, Xi Ruoyao, Mark Rutland, Joey Gouly,
Suzuki K Poulose, Zenghui Yu, Steffen Eiden, Gavin Shan,
Fuad Tabba, linux-arm-kernel, kvmarm, linux-kernel
finalise_el2_state() clears the EL2 MPAM traps whenever the ID registers
advertise MPAM, but KVM sets them only when ARM64_MPAM is set, which
also requires MPAMEN. Without EL3 the enable is EL2's own and nothing
sets it, so the cap stays off and a guest reaches the MPAM registers
while ID_AA64PFR0_EL1.MPAM reads 0 for it.
Gate the traps on the ID registers alone. MPAMEN is not a term in any
MPAM accessor, so they take effect without it. finalise_el2_state
already wrote MPAM2_EL2 under the same condition, so MPAM3_EL3.TRAPLOWER
is clear wherever the cap is set, and arm64.nompam still clears it.
Fixes: 31ff96c38ea3 ("KVM: arm64: Fix missing traps of guest accesses to the MPAM registers")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
Found this while working on the other MPAM thread [1].
[1] https://lore.kernel.org/all/CA+EHjTxeWxZiuSmnKLGLxTBXP4oJT7-LuffbPAyCSZZ5TW=5Ew@mail.gmail.com/
arch/arm64/include/asm/cpufeature.h | 5 +++++
arch/arm64/kernel/cpufeature.c | 13 +++++++++++++
arch/arm64/kvm/hyp/include/hyp/switch.h | 4 ++--
arch/arm64/tools/cpucaps | 1 +
4 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 7404a6e83a930..8863ae99596bc 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -873,6 +873,11 @@ static __always_inline bool system_supports_mpam_hcr(void)
return alternative_has_cap_unlikely(ARM64_MPAM_HCR);
}
+static __always_inline bool system_supports_mpam_sysregs(void)
+{
+ return alternative_has_cap_unlikely(ARM64_MPAM_SYSREGS);
+}
+
static inline bool system_supports_pmuv3(void)
{
return cpus_have_final_cap(ARM64_HAS_PMUV3);
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 17b83a2518a8f..36a27692e5cf7 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2501,6 +2501,13 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
return (read_sysreg_s(SYS_MPAM1_EL1) & MPAM1_EL1_MPAMEN);
}
+static bool
+test_has_mpam_sysregs(const struct arm64_cpu_capabilities *entry, int __unused)
+{
+ /* The registers exist whether or not firmware enabled MPAM. */
+ return detect_ftr_has_mpam();
+}
+
static void
cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
{
@@ -3116,6 +3123,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.matches = test_has_mpam,
.cpu_enable = cpu_enable_mpam,
},
+ {
+ .desc = "Memory Partitioning And Monitoring system registers",
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .capability = ARM64_MPAM_SYSREGS,
+ .matches = test_has_mpam_sysregs,
+ },
{
.desc = "Memory Partitioning And Monitoring Virtualisation",
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 1ce7130e25490..8941335724f6b 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -298,7 +298,7 @@ static inline void __activate_traps_mpam(struct kvm_vcpu *vcpu)
u64 clr = MPAM2_EL2_EnMPAMSM;
u64 set = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
- if (!system_supports_mpam())
+ if (!system_supports_mpam_sysregs())
return;
/* trap guest access to MPAMIDR_EL1 */
@@ -317,7 +317,7 @@ static inline void __deactivate_traps_mpam(void)
u64 clr = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1 | MPAM2_EL2_TIDR;
u64 set = MPAM2_EL2_EnMPAMSM;
- if (!system_supports_mpam())
+ if (!system_supports_mpam_sysregs())
return;
sysreg_clear_set_s(SYS_MPAM2_EL2, clr, set);
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 2775ba3359cfe..aa5be51385f68 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -78,6 +78,7 @@ KVM_PROTECTED_MODE
MISMATCHED_CACHE_TYPE
MPAM
MPAM_HCR
+MPAM_SYSREGS
MTE
MTE_ASYMM
MTE_FAR
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
--
2.39.5
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-03 16:08 [PATCH] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented Fuad Tabba
@ 2026-09-04 9:58 ` Yao Yuan
2026-09-04 11:18 ` Fuad Tabba
0 siblings, 1 reply; 4+ messages in thread
From: Yao Yuan @ 2026-09-04 9:58 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon,
James Morse, Ben Horgan, Xi Ruoyao, Mark Rutland, Joey Gouly,
Suzuki K Poulose, Zenghui Yu, Steffen Eiden, Gavin Shan,
Fuad Tabba, linux-arm-kernel, kvmarm, linux-kernel
On Thu, Sep 03, 2026 at 05:08:19PM +0800, Fuad Tabba wrote:
> finalise_el2_state() clears the EL2 MPAM traps whenever the ID registers
> advertise MPAM, but KVM sets them only when ARM64_MPAM is set, which
> also requires MPAMEN. Without EL3 the enable is EL2's own and nothing
> sets it, so the cap stays off and a guest reaches the MPAM registers
> while ID_AA64PFR0_EL1.MPAM reads 0 for it.
>
> Gate the traps on the ID registers alone. MPAMEN is not a term in any
> MPAM accessor, so they take effect without it. finalise_el2_state
> already wrote MPAM2_EL2 under the same condition, so MPAM3_EL3.TRAPLOWER
> is clear wherever the cap is set, and arm64.nompam still clears it.
>
> Fixes: 31ff96c38ea3 ("KVM: arm64: Fix missing traps of guest accesses to the MPAM registers")
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> Found this while working on the other MPAM thread [1].
>
> [1] https://lore.kernel.org/all/CA+EHjTxeWxZiuSmnKLGLxTBXP4oJT7-LuffbPAyCSZZ5TW=5Ew@mail.gmail.com/
>
> arch/arm64/include/asm/cpufeature.h | 5 +++++
> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++
> arch/arm64/kvm/hyp/include/hyp/switch.h | 4 ++--
> arch/arm64/tools/cpucaps | 1 +
> 4 files changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index 7404a6e83a930..8863ae99596bc 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -873,6 +873,11 @@ static __always_inline bool system_supports_mpam_hcr(void)
> return alternative_has_cap_unlikely(ARM64_MPAM_HCR);
> }
>
> +static __always_inline bool system_supports_mpam_sysregs(void)
> +{
> + return alternative_has_cap_unlikely(ARM64_MPAM_SYSREGS);
> +}
> +
> static inline bool system_supports_pmuv3(void)
> {
> return cpus_have_final_cap(ARM64_HAS_PMUV3);
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 17b83a2518a8f..36a27692e5cf7 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -2501,6 +2501,13 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
> return (read_sysreg_s(SYS_MPAM1_EL1) & MPAM1_EL1_MPAMEN);
> }
>
Hi Tabba,
> +static bool
> +test_has_mpam_sysregs(const struct arm64_cpu_capabilities *entry, int __unused)
> +{
> + /* The registers exist whether or not firmware enabled MPAM. */
> + return detect_ftr_has_mpam();
> +}
My understanding: arm64.nompam affects detect_ftr_has_mpam(),
thus when arm64.nompam = 1 w/ MPAM is supported in hardware,
the KVM's trap setting is skipped yet, and it's possible that
SYS_MPAM2_EL2 and SYS_MPAMHCR_EL2 are configured not trap anything
by firmware, thus guest can still access MPAM registers.
Do we need check the raw id register values for the real support
state of MPAM here ?
> +
> static void
> cpu_enable_mpam(const struct arm64_cpu_capabilities *entry)
> {
> @@ -3116,6 +3123,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
> .matches = test_has_mpam,
> .cpu_enable = cpu_enable_mpam,
> },
> + {
> + .desc = "Memory Partitioning And Monitoring system registers",
> + .type = ARM64_CPUCAP_SYSTEM_FEATURE,
> + .capability = ARM64_MPAM_SYSREGS,
> + .matches = test_has_mpam_sysregs,
> + },
> {
> .desc = "Memory Partitioning And Monitoring Virtualisation",
> .type = ARM64_CPUCAP_SYSTEM_FEATURE,
> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> index 1ce7130e25490..8941335724f6b 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> @@ -298,7 +298,7 @@ static inline void __activate_traps_mpam(struct kvm_vcpu *vcpu)
> u64 clr = MPAM2_EL2_EnMPAMSM;
> u64 set = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1;
>
> - if (!system_supports_mpam())
> + if (!system_supports_mpam_sysregs())
> return;
>
> /* trap guest access to MPAMIDR_EL1 */
> @@ -317,7 +317,7 @@ static inline void __deactivate_traps_mpam(void)
> u64 clr = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1 | MPAM2_EL2_TIDR;
> u64 set = MPAM2_EL2_EnMPAMSM;
>
> - if (!system_supports_mpam())
> + if (!system_supports_mpam_sysregs())
> return;
>
> sysreg_clear_set_s(SYS_MPAM2_EL2, clr, set);
> diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
> index 2775ba3359cfe..aa5be51385f68 100644
> --- a/arch/arm64/tools/cpucaps
> +++ b/arch/arm64/tools/cpucaps
> @@ -78,6 +78,7 @@ KVM_PROTECTED_MODE
> MISMATCHED_CACHE_TYPE
> MPAM
> MPAM_HCR
> +MPAM_SYSREGS
> MTE
> MTE_ASYMM
> MTE_FAR
>
> base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-04 9:58 ` Yao Yuan
@ 2026-09-04 11:18 ` Fuad Tabba
2026-09-04 23:07 ` Yao Yuan
0 siblings, 1 reply; 4+ messages in thread
From: Fuad Tabba @ 2026-09-04 11:18 UTC (permalink / raw)
To: Yao Yuan
Cc: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon,
James Morse, Ben Horgan, Xi Ruoyao, Mark Rutland, Joey Gouly,
Suzuki K Poulose, Zenghui Yu, Steffen Eiden, Gavin Shan,
linux-arm-kernel, kvmarm, linux-kernel
Hi Yuan,
> > +static bool
> > +test_has_mpam_sysregs(const struct arm64_cpu_capabilities *entry, int __unused)
> > +{
> > + /* The registers exist whether or not firmware enabled MPAM. */
> > + return detect_ftr_has_mpam();
> > +}
>
> My understanding: arm64.nompam affects detect_ftr_has_mpam(),
> thus when arm64.nompam = 1 w/ MPAM is supported in hardware,
> the KVM's trap setting is skipped yet, and it's possible that
> SYS_MPAM2_EL2 and SYS_MPAMHCR_EL2 are configured not trap anything
> by firmware, thus guest can still access MPAM registers.
>
> Do we need check the raw id register values for the real support
> state of MPAM here ?
Under arm64.nompam, finalise_el2_state skips the MPAM2_EL2 and
MPAMHCR_EL2 writes too, via the same check_override, so the kernel
does not clear the traps either. What a guest reaches there is
whatever EL3 left, UNKNOWN when EL3 is implemented. This patch is for
the case where the kernel cleared the traps itself and never set them
again.
Gating on the raw ID registers would make __activate_traps_mpam()
write MPAM2_EL2 on guest entry there. AFAICT that traps to EL3
wherever MPAM3_EL3.TRAPLOWER is still set, which is the firmware the
option is for: 10f885d63a0e ("arm64: Add override for MPAM") added it
for firmware that leaves the trap set and does not emulate it.
The arm64.nompam hazard is documented separately [1].
Cheers,
/fuad
[1] https://lore.kernel.org/all/20260903084809.2027326-1-fuad.tabba@linux.dev/
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-04 11:18 ` Fuad Tabba
@ 2026-09-04 23:07 ` Yao Yuan
0 siblings, 0 replies; 4+ messages in thread
From: Yao Yuan @ 2026-09-04 23:07 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Oliver Upton, Catalin Marinas, Will Deacon,
James Morse, Ben Horgan, Xi Ruoyao, Mark Rutland, Joey Gouly,
Suzuki K Poulose, Zenghui Yu, Steffen Eiden, Gavin Shan,
linux-arm-kernel, kvmarm, linux-kernel
On Fri, Sep 04, 2026 at 12:18:00PM +0800, Fuad Tabba wrote:
> Hi Yuan,
>
> > > +static bool
> > > +test_has_mpam_sysregs(const struct arm64_cpu_capabilities *entry, int __unused)
> > > +{
> > > + /* The registers exist whether or not firmware enabled MPAM. */
> > > + return detect_ftr_has_mpam();
> > > +}
> >
> > My understanding: arm64.nompam affects detect_ftr_has_mpam(),
> > thus when arm64.nompam = 1 w/ MPAM is supported in hardware,
> > the KVM's trap setting is skipped yet, and it's possible that
> > SYS_MPAM2_EL2 and SYS_MPAMHCR_EL2 are configured not trap anything
> > by firmware, thus guest can still access MPAM registers.
> >
> > Do we need check the raw id register values for the real support
> > state of MPAM here ?
>
> Under arm64.nompam, finalise_el2_state skips the MPAM2_EL2 and
> MPAMHCR_EL2 writes too, via the same check_override, so the kernel
> does not clear the traps either. What a guest reaches there is
> whatever EL3 left, UNKNOWN when EL3 is implemented.
That's what I was worried before w/ nompam = 1 for guest can still access
the MPAM registers. Now it's fine to me w/ limitation on usage of nompam
described in [1], the limitation on guest behavior described there yet.
Thanks for the reply! I just not aware [1] before.
> This patch is for the case where the kernel cleared the traps itself and
> never set them again.
Yes next time I will explicitly say want to discuss something may
related to the patch's main purpose.
>
> Gating on the raw ID registers would make __activate_traps_mpam()
> write MPAM2_EL2 on guest entry there. AFAICT that traps to EL3
> wherever MPAM3_EL3.TRAPLOWER is still set, which is the firmware the
> option is for: 10f885d63a0e ("arm64: Add override for MPAM") added it
> for firmware that leaves the trap set and does not emulate it.
Make sense, it break the nompam actually on platform need it,
this isn't good idea.
For the purpose of this patch:
Reviewed-by: Yuan Yao <yaoyuan@linux.alibaba.com>
>
> The arm64.nompam hazard is documented separately [1].
>
> Cheers,
> /fuad
>
> [1] https://lore.kernel.org/all/20260903084809.2027326-1-fuad.tabba@linux.dev/
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-04 23:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 16:08 [PATCH] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented Fuad Tabba
2026-09-04 9:58 ` Yao Yuan
2026-09-04 11:18 ` Fuad Tabba
2026-09-04 23:07 ` Yao Yuan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox