* [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
@ 2026-09-08 14:56 Fuad Tabba
2026-09-10 10:40 ` Will Deacon
2026-09-10 11:08 ` Marc Zyngier
0 siblings, 2 replies; 5+ messages in thread
From: Fuad Tabba @ 2026-09-08 14:56 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,
Yuan Yao, Fuad Tabba, linux-arm-kernel, kvmarm, linux-kernel
finalise_el2_state() clears the EL2 MPAM traps whenever the ID
registers advertise MPAM, while KVM sets them only under ARM64_MPAM,
which also requires MPAMEN. Without EL3 nothing sets that enable, so a
guest reaches the MPAM registers while ID_AA64PFR0_EL1.MPAM reads 0
for it.
Gate the traps on the ID registers alone: MPAMEN isn't a term in any
MPAM accessor, so they take effect without it. The cap tests the
sanitised ID fields, which never exceed a CPU's own, so it's set only
where finalise_el2_state already wrote MPAM2_EL2. MPAM3_EL3.TRAPLOWER
is clear there, and arm64.nompam turns the cap off too.
Fixes: 23b33d1e168c ("arm64: head.S: Initialise MPAM EL2 registers and disable traps")
Reviewed-by: Yuan Yao <yaoyuan@linux.alibaba.com>
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
Notes:
Changes since v1:
- Commit message only. The code is unchanged, so Yuan Yao's
Reviewed-by is carried.
- Fixes: names the commit that cleared the traps, rather than the
one that added KVM's trapping.
- Says why the sanitised ID fields are the safe gate: the cap is set
only where finalise_el2_state already wrote MPAM2_EL2.
Not covered, and answered on the v1 thread: a machine whose CPUs
differ on MPAM, raised by Ben and by sashiko.
v1: https://lore.kernel.org/all/20260903160819.831518-1-fuad.tabba@linux.dev/
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
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-08 14:56 [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented Fuad Tabba
@ 2026-09-10 10:40 ` Will Deacon
2026-09-11 7:01 ` Fuad Tabba
2026-09-10 11:08 ` Marc Zyngier
1 sibling, 1 reply; 5+ messages in thread
From: Will Deacon @ 2026-09-10 10:40 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Oliver Upton, Catalin Marinas, James Morse,
Ben Horgan, Xi Ruoyao, Mark Rutland, Joey Gouly,
Suzuki K Poulose, Zenghui Yu, Steffen Eiden, Gavin Shan,
Yuan Yao, Fuad Tabba, linux-arm-kernel, kvmarm, linux-kernel
On Tue, Sep 08, 2026 at 03:56:51PM +0100, Fuad Tabba wrote:
> finalise_el2_state() clears the EL2 MPAM traps whenever the ID
> registers advertise MPAM, while KVM sets them only under ARM64_MPAM,
> which also requires MPAMEN. Without EL3 nothing sets that enable, so a
> guest reaches the MPAM registers while ID_AA64PFR0_EL1.MPAM reads 0
> for it.
>
> Gate the traps on the ID registers alone: MPAMEN isn't a term in any
> MPAM accessor, so they take effect without it. The cap tests the
> sanitised ID fields, which never exceed a CPU's own, so it's set only
> where finalise_el2_state already wrote MPAM2_EL2. MPAM3_EL3.TRAPLOWER
> is clear there, and arm64.nompam turns the cap off too.
>
> Fixes: 23b33d1e168c ("arm64: head.S: Initialise MPAM EL2 registers and disable traps")
> Reviewed-by: Yuan Yao <yaoyuan@linux.alibaba.com>
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
>
> Notes:
> Changes since v1:
> - Commit message only. The code is unchanged, so Yuan Yao's
> Reviewed-by is carried.
> - Fixes: names the commit that cleared the traps, rather than the
> one that added KVM's trapping.
> - Says why the sanitised ID fields are the safe gate: the cap is set
> only where finalise_el2_state already wrote MPAM2_EL2.
>
> Not covered, and answered on the v1 thread: a machine whose CPUs
> differ on MPAM, raised by Ben and by sashiko.
>
> v1: https://lore.kernel.org/all/20260903160819.831518-1-fuad.tabba@linux.dev/
>
> 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,
> + },
We already have two system capabilities for MPAM so I'm not overly keen
to add a third, especially as the MPAM code is largely confined to the
resctrl driver. In fact, this feels a bit similar to things like TRBE
and SPE in the sense that (a) we have to probe it per-cpu (b) it can
be disabled by a higher EL and (c) most of the code is in a driver, but
KVM needs to know how to switch it.
Neither TRBE nor SPE need entries in arm64_features[] at all, so something
isn't right here...
Will
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-08 14:56 [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented Fuad Tabba
2026-09-10 10:40 ` Will Deacon
@ 2026-09-10 11:08 ` Marc Zyngier
2026-09-11 10:43 ` Fuad Tabba
1 sibling, 1 reply; 5+ messages in thread
From: Marc Zyngier @ 2026-09-10 11:08 UTC (permalink / raw)
To: Fuad Tabba
Cc: 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,
Yuan Yao, Fuad Tabba, linux-arm-kernel, kvmarm, linux-kernel
On Tue, 08 Sep 2026 15:56:51 +0100,
Fuad Tabba <fuad.tabba@linux.dev> wrote:
>
> finalise_el2_state() clears the EL2 MPAM traps whenever the ID
> registers advertise MPAM, while KVM sets them only under ARM64_MPAM,
> which also requires MPAMEN. Without EL3 nothing sets that enable, so a
> guest reaches the MPAM registers while ID_AA64PFR0_EL1.MPAM reads 0
> for it.
>
> Gate the traps on the ID registers alone: MPAMEN isn't a term in any
> MPAM accessor, so they take effect without it. The cap tests the
> sanitised ID fields, which never exceed a CPU's own, so it's set only
> where finalise_el2_state already wrote MPAM2_EL2. MPAM3_EL3.TRAPLOWER
> is clear there, and arm64.nompam turns the cap off too.
>
> Fixes: 23b33d1e168c ("arm64: head.S: Initialise MPAM EL2 registers and disable traps")
> Reviewed-by: Yuan Yao <yaoyuan@linux.alibaba.com>
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
>
> Notes:
> Changes since v1:
> - Commit message only. The code is unchanged, so Yuan Yao's
> Reviewed-by is carried.
> - Fixes: names the commit that cleared the traps, rather than the
> one that added KVM's trapping.
> - Says why the sanitised ID fields are the safe gate: the cap is set
> only where finalise_el2_state already wrote MPAM2_EL2.
>
> Not covered, and answered on the v1 thread: a machine whose CPUs
> differ on MPAM, raised by Ben and by sashiko.
>
> v1: https://lore.kernel.org/all/20260903160819.831518-1-fuad.tabba@linux.dev/
>
> 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);
> +}
> +
What is the rationale for choosing alternative_has_cap_unlikely()
instead of cpus_have_final_cap(), which is more wildly used?
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-10 10:40 ` Will Deacon
@ 2026-09-11 7:01 ` Fuad Tabba
0 siblings, 0 replies; 5+ messages in thread
From: Fuad Tabba @ 2026-09-11 7:01 UTC (permalink / raw)
To: Will Deacon
Cc: Marc Zyngier, Oliver Upton, Catalin Marinas, James Morse,
Ben Horgan, Xi Ruoyao, Mark Rutland, Joey Gouly,
Suzuki K Poulose, Zenghui Yu, Steffen Eiden, Gavin Shan,
Yuan Yao, linux-arm-kernel, kvmarm, linux-kernel
On Thu, 10 Sept 2026 at 11:40, Will Deacon <will@kernel.org> wrote:
...
> > +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,
> > + },
>
> We already have two system capabilities for MPAM so I'm not overly keen
> to add a third, especially as the MPAM code is largely confined to the
> resctrl driver. In fact, this feels a bit similar to things like TRBE
> and SPE in the sense that (a) we have to probe it per-cpu (b) it can
> be disabled by a higher EL and (c) most of the code is in a driver, but
> KVM needs to know how to switch it.
>
> Neither TRBE nor SPE need entries in arm64_features[] at all, so something
> isn't right here...
I think I've overthunk it. The problem isn't in what the host is
doing, but that KVM is basing its traps on whether MPAM support exists
and whether that support is enabled.
V3 should be more in line with what you're suggesting...
Cheers,
/fuad
>
> Will
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented
2026-09-10 11:08 ` Marc Zyngier
@ 2026-09-11 10:43 ` Fuad Tabba
0 siblings, 0 replies; 5+ messages in thread
From: Fuad Tabba @ 2026-09-11 10:43 UTC (permalink / raw)
To: Marc Zyngier
Cc: 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,
Yuan Yao, linux-arm-kernel, kvmarm, linux-kernel
On Thu, 10 Sept 2026 at 12:08, Marc Zyngier <maz@kernel.org> wrote:
...
> > --- 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);
> > +}
> > +
>
> What is the rationale for choosing alternative_has_cap_unlikely()
> instead of cpus_have_final_cap(), which is more wildly used?
Not a good one to be honest, and it's gone in V3.
Cheers,
/fuad
>
> M.
>
> --
> Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-11 10:44 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-08 14:56 [PATCH v2] KVM: arm64: Trap guest MPAM accesses whenever MPAM is implemented Fuad Tabba
2026-09-10 10:40 ` Will Deacon
2026-09-11 7:01 ` Fuad Tabba
2026-09-10 11:08 ` Marc Zyngier
2026-09-11 10:43 ` Fuad Tabba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®