* [PATCH 1/4] arm64/fpsimd: Introduce __bit_to_vl() helper
2024-06-05 11:41 [PATCH 0/4] KVM: arm64: Fix underallocation of storage for SVE state Mark Brown
@ 2024-06-05 11:41 ` Mark Brown
2024-06-05 11:41 ` [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU Mark Brown
` (2 subsequent siblings)
3 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2024-06-05 11:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, Fuad Tabba
Cc: linux-arm-kernel, linux-kernel, kvmarm, Mark Brown
In all cases where we use the existing __bit_to_vq() helper we immediately
convert the result into a VL. Provide and use __bit_to_vl() doing this
directly.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
arch/arm64/include/asm/fpsimd.h | 4 ++++
arch/arm64/kernel/fpsimd.c | 12 ++++++------
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index bc69ac368d73..51c21265b4fa 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -172,6 +172,10 @@ static inline unsigned int __bit_to_vq(unsigned int bit)
return SVE_VQ_MAX - bit;
}
+static inline unsigned int __bit_to_vl(unsigned int bit)
+{
+ return sve_vl_from_vq(__bit_to_vq(bit));
+}
struct vl_info {
enum vec_type type;
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 82e8a6017382..22542fb81812 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -530,7 +530,7 @@ static unsigned int find_supported_vector_length(enum vec_type type,
bit = find_next_bit(info->vq_map, SVE_VQ_MAX,
__vq_to_bit(sve_vq_from_vl(vl)));
- return sve_vl_from_vq(__bit_to_vq(bit));
+ return __bit_to_vl(bit);
}
#if defined(CONFIG_ARM64_SVE) && defined(CONFIG_SYSCTL)
@@ -1103,7 +1103,7 @@ int vec_verify_vq_map(enum vec_type type)
* Mismatches above sve_max_virtualisable_vl are fine, since
* no guest is allowed to configure ZCR_EL2.LEN to exceed this:
*/
- if (sve_vl_from_vq(__bit_to_vq(b)) <= info->max_virtualisable_vl) {
+ if (__bit_to_vl(b) <= info->max_virtualisable_vl) {
pr_warn("%s: cpu%d: Unsupported vector length(s) present\n",
info->name, smp_processor_id());
return -EINVAL;
@@ -1169,7 +1169,7 @@ void __init sve_setup(void)
set_bit(__vq_to_bit(SVE_VQ_MIN), info->vq_map);
max_bit = find_first_bit(info->vq_map, SVE_VQ_MAX);
- info->max_vl = sve_vl_from_vq(__bit_to_vq(max_bit));
+ info->max_vl = __bit_to_vl(max_bit);
/*
* For the default VL, pick the maximum supported value <= 64.
@@ -1188,7 +1188,7 @@ void __init sve_setup(void)
/* No virtualisable VLs? This is architecturally forbidden. */
info->max_virtualisable_vl = SVE_VQ_MIN;
else /* b + 1 < SVE_VQ_MAX */
- info->max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
+ info->max_virtualisable_vl = __bit_to_vl(b + 1);
if (info->max_virtualisable_vl > info->max_vl)
info->max_virtualisable_vl = info->max_vl;
@@ -1305,10 +1305,10 @@ void __init sme_setup(void)
WARN_ON(bitmap_empty(info->vq_map, SVE_VQ_MAX));
min_bit = find_last_bit(info->vq_map, SVE_VQ_MAX);
- info->min_vl = sve_vl_from_vq(__bit_to_vq(min_bit));
+ info->min_vl = __bit_to_vl(min_bit);
max_bit = find_first_bit(info->vq_map, SVE_VQ_MAX);
- info->max_vl = sve_vl_from_vq(__bit_to_vq(max_bit));
+ info->max_vl = __bit_to_vl(max_bit);
WARN_ON(info->min_vl > info->max_vl);
--
2.39.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU
2024-06-05 11:41 [PATCH 0/4] KVM: arm64: Fix underallocation of storage for SVE state Mark Brown
2024-06-05 11:41 ` [PATCH 1/4] arm64/fpsimd: Introduce __bit_to_vl() helper Mark Brown
@ 2024-06-05 11:41 ` Mark Brown
2024-06-05 12:03 ` Fuad Tabba
2024-06-05 12:13 ` Marc Zyngier
2024-06-05 11:41 ` [PATCH 3/4] KVM: arm64: Fix FFR offset calculation for pKVM host state save and restore Mark Brown
2024-06-05 11:41 ` [PATCH 4/4] KVM: arm64: Avoid underallocating storage for host SVE state Mark Brown
3 siblings, 2 replies; 11+ messages in thread
From: Mark Brown @ 2024-06-05 11:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, Fuad Tabba
Cc: linux-arm-kernel, linux-kernel, kvmarm, Mark Brown
When discovering the vector lengths for SVE and SME we do not currently
record the maximum VL supported on any individual CPU. This is expected
to be the same for all CPUs but the architecture allows asymmetry, if we
do encounter an asymmetric system then some CPUs may support VLs higher
than the maximum Linux will use. Since the pKVM hypervisor needs to
support saving and restoring anything the host can physically set it
needs to know the maximum value any CPU could have, add support for
enumerating it and validation for late CPUs.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
arch/arm64/include/asm/fpsimd.h | 13 +++++++++++++
arch/arm64/kernel/fpsimd.c | 26 +++++++++++++++++++++++++-
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 51c21265b4fa..cd19713c9deb 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -188,6 +188,9 @@ struct vl_info {
int max_vl;
int max_virtualisable_vl;
+ /* Maximum vector length observed on any CPU */
+ int max_cpu_vl;
+
/*
* Set of available vector lengths,
* where length vq encoded as bit __vq_to_bit(vq):
@@ -278,6 +281,11 @@ static inline int vec_max_virtualisable_vl(enum vec_type type)
return vl_info[type].max_virtualisable_vl;
}
+static inline int vec_max_cpu_vl(enum vec_type type)
+{
+ return vl_info[type].max_cpu_vl;
+}
+
static inline int sve_max_vl(void)
{
return vec_max_vl(ARM64_VEC_SVE);
@@ -288,6 +296,11 @@ static inline int sve_max_virtualisable_vl(void)
return vec_max_virtualisable_vl(ARM64_VEC_SVE);
}
+static inline int sve_max_cpu_vl(void)
+{
+ return vec_max_cpu_vl(ARM64_VEC_SVE);
+}
+
/* Ensure vq >= SVE_VQ_MIN && vq <= SVE_VQ_MAX before calling this function */
static inline bool vq_available(enum vec_type type, unsigned int vq)
{
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 22542fb81812..27f3593547f1 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -129,6 +129,7 @@ __ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = {
.min_vl = SVE_VL_MIN,
.max_vl = SVE_VL_MIN,
.max_virtualisable_vl = SVE_VL_MIN,
+ .max_cpu_vl = SVE_VL_MIN,
},
#endif
#ifdef CONFIG_ARM64_SME
@@ -1041,8 +1042,13 @@ static void vec_probe_vqs(struct vl_info *info,
void __init vec_init_vq_map(enum vec_type type)
{
struct vl_info *info = &vl_info[type];
+ unsigned long b;
+
vec_probe_vqs(info, info->vq_map);
bitmap_copy(info->vq_partial_map, info->vq_map, SVE_VQ_MAX);
+
+ b = find_first_bit(info->vq_map, SVE_VQ_MAX);
+ info->max_cpu_vl = __bit_to_vl(b);
}
/*
@@ -1054,11 +1060,16 @@ void vec_update_vq_map(enum vec_type type)
{
struct vl_info *info = &vl_info[type];
DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
+ unsigned long b;
vec_probe_vqs(info, tmp_map);
bitmap_and(info->vq_map, info->vq_map, tmp_map, SVE_VQ_MAX);
bitmap_or(info->vq_partial_map, info->vq_partial_map, tmp_map,
SVE_VQ_MAX);
+
+ b = find_first_bit(tmp_map, SVE_VQ_MAX);
+ if (__bit_to_vl(b) > info->max_cpu_vl)
+ info->max_cpu_vl = __bit_to_vl(b);
}
/*
@@ -1069,9 +1080,10 @@ int vec_verify_vq_map(enum vec_type type)
{
struct vl_info *info = &vl_info[type];
DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
- unsigned long b;
+ unsigned long b, max_vl;
vec_probe_vqs(info, tmp_map);
+ max_vl = __bit_to_vl(find_first_bit(tmp_map, SVE_VQ_MAX));
bitmap_complement(tmp_map, tmp_map, SVE_VQ_MAX);
if (bitmap_intersects(tmp_map, info->vq_map, SVE_VQ_MAX)) {
@@ -1083,6 +1095,18 @@ int vec_verify_vq_map(enum vec_type type)
if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
return 0;
+ /*
+ * pKVM allocates and uses storage for host state based on the
+ * largest per-PE VL, reject new PEs with a larger maximum.
+ */
+ if (is_protected_kvm_enabled()) {
+ if (max_vl > info->max_cpu_vl) {
+ pr_warn("%s: cpu%d: would increase maximum VL\n",
+ info->name, smp_processor_id());
+ return -EINVAL;
+ }
+ }
+
/*
* For KVM, it is necessary to ensure that this CPU doesn't
* support any vector length that guests may have probed as
--
2.39.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU
2024-06-05 11:41 ` [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU Mark Brown
@ 2024-06-05 12:03 ` Fuad Tabba
2024-06-05 12:56 ` Mark Brown
2024-06-05 12:13 ` Marc Zyngier
1 sibling, 1 reply; 11+ messages in thread
From: Fuad Tabba @ 2024-06-05 12:03 UTC (permalink / raw)
To: Mark Brown
Cc: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, linux-arm-kernel, linux-kernel,
kvmarm
Hi Mark,
On Wed, Jun 5, 2024 at 12:50 PM Mark Brown <broonie@kernel.org> wrote:
>
> When discovering the vector lengths for SVE and SME we do not currently
> record the maximum VL supported on any individual CPU. This is expected
> to be the same for all CPUs but the architecture allows asymmetry, if we
> do encounter an asymmetric system then some CPUs may support VLs higher
> than the maximum Linux will use. Since the pKVM hypervisor needs to
> support saving and restoring anything the host can physically set it
> needs to know the maximum value any CPU could have, add support for
> enumerating it and validation for late CPUs.
>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> arch/arm64/include/asm/fpsimd.h | 13 +++++++++++++
> arch/arm64/kernel/fpsimd.c | 26 +++++++++++++++++++++++++-
> 2 files changed, 38 insertions(+), 1 deletion(-)
Actually, I was working on fixing it and was about to send this, which
I think might be a bit simpler than what you have. Let me know what
you think and I'll send it as a proper patch if you agree:
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index bc69ac368d73..8bde13b7faa3 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -184,6 +184,9 @@ struct vl_info {
int max_vl;
int max_virtualisable_vl;
+ /* The maximum vl encountered for any cpu in the system. */
+ int max_system_vl;
+
/*
* Set of available vector lengths,
* where length vq encoded as bit __vq_to_bit(vq):
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 82e8a6017382..e0af4c3c9a40 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -1006,7 +1006,7 @@ int sme_get_current_vl(void)
static void vec_probe_vqs(struct vl_info *info,
DECLARE_BITMAP(map, SVE_VQ_MAX))
{
- unsigned int vq, vl;
+ unsigned int vq, vl, max_vl = 0;
bitmap_zero(map, SVE_VQ_MAX);
@@ -1031,7 +1031,12 @@ static void vec_probe_vqs(struct vl_info *info,
vq = sve_vq_from_vl(vl); /* skip intervening lengths */
set_bit(__vq_to_bit(vq), map);
+
+ if (!max_vl)
+ max_vl = vl;
}
+
+ info->max_system_vl = max((int) max_vl, info->max_system_vl);
}
/*
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 3fc8ca164dbe..9f751cce8081 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -52,7 +52,7 @@ int __init kvm_arm_init_sve(void)
{
if (system_supports_sve()) {
kvm_sve_max_vl = sve_max_virtualisable_vl();
- kvm_host_sve_max_vl = sve_max_vl();
+ kvm_host_sve_max_vl = vl_info[ARM64_VEC_SVE].max_system_vl;
kvm_nvhe_sym(kvm_host_sve_max_vl) = kvm_host_sve_max_vl;
/*
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU
2024-06-05 12:03 ` Fuad Tabba
@ 2024-06-05 12:56 ` Mark Brown
0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2024-06-05 12:56 UTC (permalink / raw)
To: Fuad Tabba
Cc: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, linux-arm-kernel, linux-kernel,
kvmarm
[-- Attachment #1.1: Type: text/plain, Size: 1240 bytes --]
On Wed, Jun 05, 2024 at 01:03:16PM +0100, Fuad Tabba wrote:
> Actually, I was working on fixing it and was about to send this, which
> I think might be a bit simpler than what you have. Let me know what
> you think and I'll send it as a proper patch if you agree:
> +
> + if (!max_vl)
> + max_vl = vl;
> }
> +
> + info->max_system_vl = max((int) max_vl, info->max_system_vl);
Yeah, I originally had written something like this (just doing the max
in the original assignment rather than staging in a local variable) but
it didn't feel great and like it was more vulnerable to getting missed
if we do more parallel bringup so I switched to keeping the split
between enumeration and integration.
I do also prefer the _cpu_ naming since _system_ could be read as the
maximum that we're actually using in the system, as with any naming
thing it's all a bit bikesheddy.
> if (system_supports_sve()) {
> kvm_sve_max_vl = sve_max_virtualisable_vl();
> - kvm_host_sve_max_vl = sve_max_vl();
> + kvm_host_sve_max_vl = vl_info[ARM64_VEC_SVE].max_system_vl;
We should keep the accessor functions, it's more consistent and supports
refactoring.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU
2024-06-05 11:41 ` [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU Mark Brown
2024-06-05 12:03 ` Fuad Tabba
@ 2024-06-05 12:13 ` Marc Zyngier
2024-06-05 12:31 ` Mark Brown
1 sibling, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2024-06-05 12:13 UTC (permalink / raw)
To: Mark Brown
Cc: Catalin Marinas, Will Deacon, Oliver Upton, James Morse,
Suzuki K Poulose, Fuad Tabba, linux-arm-kernel, linux-kernel,
kvmarm
On Wed, 05 Jun 2024 12:41:28 +0100,
Mark Brown <broonie@kernel.org> wrote:
>
> @@ -1083,6 +1095,18 @@ int vec_verify_vq_map(enum vec_type type)
> if (!IS_ENABLED(CONFIG_KVM) || !is_hyp_mode_available())
> return 0;
>
> + /*
> + * pKVM allocates and uses storage for host state based on the
> + * largest per-PE VL, reject new PEs with a larger maximum.
> + */
> + if (is_protected_kvm_enabled()) {
> + if (max_vl > info->max_cpu_vl) {
> + pr_warn("%s: cpu%d: would increase maximum VL\n",
> + info->name, smp_processor_id());
> + return -EINVAL;
> + }
> + }
> +
Once protected mode is enabled, no new CPU can be booted (see
psci_relay.c::psci_cpu_on()).
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU
2024-06-05 12:13 ` Marc Zyngier
@ 2024-06-05 12:31 ` Mark Brown
0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2024-06-05 12:31 UTC (permalink / raw)
To: Marc Zyngier
Cc: Catalin Marinas, Will Deacon, Oliver Upton, James Morse,
Suzuki K Poulose, Fuad Tabba, linux-arm-kernel, linux-kernel,
kvmarm
[-- Attachment #1.1: Type: text/plain, Size: 777 bytes --]
On Wed, Jun 05, 2024 at 01:13:20PM +0100, Marc Zyngier wrote:
> Mark Brown <broonie@kernel.org> wrote:
> > + /*
> > + * pKVM allocates and uses storage for host state based on the
> > + * largest per-PE VL, reject new PEs with a larger maximum.
> > + */
> > + if (is_protected_kvm_enabled()) {
> > + if (max_vl > info->max_cpu_vl) {
> > + pr_warn("%s: cpu%d: would increase maximum VL\n",
> > + info->name, smp_processor_id());
> > + return -EINVAL;
> > + }
> > + }
> Once protected mode is enabled, no new CPU can be booted (see
> psci_relay.c::psci_cpu_on()).
Ah, that's a bit easier. Might still be worth keeping the check just in
case that changes or we acquire some further use of this value but it's
not currently needed and the comment could be updated.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/4] KVM: arm64: Fix FFR offset calculation for pKVM host state save and restore
2024-06-05 11:41 [PATCH 0/4] KVM: arm64: Fix underallocation of storage for SVE state Mark Brown
2024-06-05 11:41 ` [PATCH 1/4] arm64/fpsimd: Introduce __bit_to_vl() helper Mark Brown
2024-06-05 11:41 ` [PATCH 2/4] arm64/fpsimd: Discover maximum vector length implemented by any CPU Mark Brown
@ 2024-06-05 11:41 ` Mark Brown
2024-06-05 12:12 ` Fuad Tabba
2024-06-05 11:41 ` [PATCH 4/4] KVM: arm64: Avoid underallocating storage for host SVE state Mark Brown
3 siblings, 1 reply; 11+ messages in thread
From: Mark Brown @ 2024-06-05 11:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, Fuad Tabba
Cc: linux-arm-kernel, linux-kernel, kvmarm, Mark Brown
When saving and restoring the SVE state for the host we configure the
hardware for the maximum VL it supports, but when calculating offsets in
memory we use the maximum usable VL for the host. Since these two values
may not be the same this may result in data corruption. We can just
read the current VL from the hardware with an instruction so do that
instead of a saved value.
Fixes: b5b9955617bc ("KVM: arm64: Eagerly restore host fpsimd/sve state in pKVM")
Signed-off-by: Mark Brown <broonie@kernel.org>
---
arch/arm64/include/asm/kvm_hyp.h | 1 +
arch/arm64/kvm/hyp/fpsimd.S | 5 +++++
arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 2 +-
4 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index b05bceca3385..7510383d78a6 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -113,6 +113,7 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
void __sve_save_state(void *sve_pffr, u32 *fpsr, int save_ffr);
void __sve_restore_state(void *sve_pffr, u32 *fpsr, int restore_ffr);
+int __sve_get_vl(void);
u64 __guest_enter(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/fpsimd.S b/arch/arm64/kvm/hyp/fpsimd.S
index e950875e31ce..d272dbf36da8 100644
--- a/arch/arm64/kvm/hyp/fpsimd.S
+++ b/arch/arm64/kvm/hyp/fpsimd.S
@@ -31,3 +31,8 @@ SYM_FUNC_START(__sve_save_state)
sve_save 0, x1, x2, 3
ret
SYM_FUNC_END(__sve_save_state)
+
+SYM_FUNC_START(__sve_get_vl)
+ _sve_rdvl 0, 1
+ ret
+SYM_FUNC_END(__sve_get_vl)
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 0c4de44534b7..06efcca765cc 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -327,7 +327,7 @@ static inline void __hyp_sve_save_host(void)
sve_state->zcr_el1 = read_sysreg_el1(SYS_ZCR);
write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
- __sve_save_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
+ __sve_save_state(sve_state->sve_regs + sve_ffr_offset(__sve_get_vl()),
&sve_state->fpsr,
true);
}
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index f43d845f3c4e..bd8f671e848c 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -49,7 +49,7 @@ static void __hyp_sve_restore_host(void)
* supported by the system (or limited at EL3).
*/
write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
- __sve_restore_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
+ __sve_restore_state(sve_state->sve_regs + sve_ffr_offset(__sve_get_vl()),
&sve_state->fpsr,
true);
write_sysreg_el1(sve_state->zcr_el1, SYS_ZCR);
--
2.39.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 3/4] KVM: arm64: Fix FFR offset calculation for pKVM host state save and restore
2024-06-05 11:41 ` [PATCH 3/4] KVM: arm64: Fix FFR offset calculation for pKVM host state save and restore Mark Brown
@ 2024-06-05 12:12 ` Fuad Tabba
2024-06-05 13:17 ` Mark Brown
0 siblings, 1 reply; 11+ messages in thread
From: Fuad Tabba @ 2024-06-05 12:12 UTC (permalink / raw)
To: Mark Brown
Cc: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, linux-arm-kernel, linux-kernel,
kvmarm
Hi Mark,
On Wed, Jun 5, 2024 at 12:50 PM Mark Brown <broonie@kernel.org> wrote:
>
> When saving and restoring the SVE state for the host we configure the
> hardware for the maximum VL it supports, but when calculating offsets in
> memory we use the maximum usable VL for the host. Since these two values
> may not be the same this may result in data corruption. We can just
> read the current VL from the hardware with an instruction so do that
> instead of a saved value.
>
> Fixes: b5b9955617bc ("KVM: arm64: Eagerly restore host fpsimd/sve state in pKVM")
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> arch/arm64/include/asm/kvm_hyp.h | 1 +
> arch/arm64/kvm/hyp/fpsimd.S | 5 +++++
> arch/arm64/kvm/hyp/include/hyp/switch.h | 2 +-
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 2 +-
> 4 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index b05bceca3385..7510383d78a6 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -113,6 +113,7 @@ void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
> void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
> void __sve_save_state(void *sve_pffr, u32 *fpsr, int save_ffr);
> void __sve_restore_state(void *sve_pffr, u32 *fpsr, int restore_ffr);
> +int __sve_get_vl(void);
>
> u64 __guest_enter(struct kvm_vcpu *vcpu);
>
> diff --git a/arch/arm64/kvm/hyp/fpsimd.S b/arch/arm64/kvm/hyp/fpsimd.S
> index e950875e31ce..d272dbf36da8 100644
> --- a/arch/arm64/kvm/hyp/fpsimd.S
> +++ b/arch/arm64/kvm/hyp/fpsimd.S
> @@ -31,3 +31,8 @@ SYM_FUNC_START(__sve_save_state)
> sve_save 0, x1, x2, 3
> ret
> SYM_FUNC_END(__sve_save_state)
> +
> +SYM_FUNC_START(__sve_get_vl)
> + _sve_rdvl 0, 1
> + ret
> +SYM_FUNC_END(__sve_get_vl)
> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> index 0c4de44534b7..06efcca765cc 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> @@ -327,7 +327,7 @@ static inline void __hyp_sve_save_host(void)
>
> sve_state->zcr_el1 = read_sysreg_el1(SYS_ZCR);
> write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
> - __sve_save_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
> + __sve_save_state(sve_state->sve_regs + sve_ffr_offset(__sve_get_vl()),
> &sve_state->fpsr,
> true);
> }
If my understanding of the spec is correct (which more often than not
it isn't), I don't think we have an issue as long as we use the same
value in the offset on saving/restoring, and that that value
represents the maximum possible value.
On the other hand, if my understanding is wrong, then we might need to
also fix __efi_fpsimd_begin()/__efi_fpsimd_end() in
arch/arm64/kernel/fpsimd.c, as well as vcpu_sve_pffr() in
arch/arm64/include/asm/kvm_host.h
What do you think?
/fuad
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index f43d845f3c4e..bd8f671e848c 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -49,7 +49,7 @@ static void __hyp_sve_restore_host(void)
> * supported by the system (or limited at EL3).
> */
> write_sysreg_s(ZCR_ELx_LEN_MASK, SYS_ZCR_EL2);
> - __sve_restore_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
> + __sve_restore_state(sve_state->sve_regs + sve_ffr_offset(__sve_get_vl()),
> &sve_state->fpsr,
> true);
> write_sysreg_el1(sve_state->zcr_el1, SYS_ZCR);
>
> --
> 2.39.2
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 3/4] KVM: arm64: Fix FFR offset calculation for pKVM host state save and restore
2024-06-05 12:12 ` Fuad Tabba
@ 2024-06-05 13:17 ` Mark Brown
0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2024-06-05 13:17 UTC (permalink / raw)
To: Fuad Tabba
Cc: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, linux-arm-kernel, linux-kernel,
kvmarm
[-- Attachment #1.1: Type: text/plain, Size: 576 bytes --]
On Wed, Jun 05, 2024 at 01:12:34PM +0100, Fuad Tabba wrote:
> If my understanding of the spec is correct (which more often than not
> it isn't), I don't think we have an issue as long as we use the same
> value in the offset on saving/restoring, and that that value
> represents the maximum possible value.
Yes, we could also correct the issue by switching to use the system
enumerated maximum but that still leaves us setting one value and then
immediately assuming a different value. Reading the actual VL from the
hardware makes the code more obviously self consistent.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 4/4] KVM: arm64: Avoid underallocating storage for host SVE state
2024-06-05 11:41 [PATCH 0/4] KVM: arm64: Fix underallocation of storage for SVE state Mark Brown
` (2 preceding siblings ...)
2024-06-05 11:41 ` [PATCH 3/4] KVM: arm64: Fix FFR offset calculation for pKVM host state save and restore Mark Brown
@ 2024-06-05 11:41 ` Mark Brown
3 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2024-06-05 11:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Marc Zyngier, Oliver Upton,
James Morse, Suzuki K Poulose, Fuad Tabba
Cc: linux-arm-kernel, linux-kernel, kvmarm, Mark Brown
We size the allocation for the host SVE state using the maximum VL
shared by all CPUs in the host. As observed during review on an
asymmetric system this may be less than the maximum VL supported on some
of the CPUs. Since the pKVM hypervisor saves and restores the host
state using the maximum VL for the current CPU this may lead to buffer
overflows, fix this by changing pKVM to use the maximum VL for any CPU
to size allocations and limit host configurations.
Fixes: 66d5b53e20a6 ("KVM: arm64: Allocate memory mapped at hyp for host sve state in pKVM")
Signed-off-by: Mark Brown <broonie@kernel.org>
---
arch/arm64/include/asm/kvm_host.h | 2 +-
arch/arm64/include/asm/kvm_hyp.h | 2 +-
arch/arm64/include/asm/kvm_pkvm.h | 2 +-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 4 ++--
arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +-
arch/arm64/kvm/reset.c | 6 +++---
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 36b8e97bf49e..a28fae10596f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -76,7 +76,7 @@ static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; };
DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
extern unsigned int __ro_after_init kvm_sve_max_vl;
-extern unsigned int __ro_after_init kvm_host_sve_max_vl;
+extern unsigned int __ro_after_init kvm_host_sve_max_cpu_vl;
int __init kvm_arm_init_sve(void);
u32 __attribute_const__ kvm_target_cpu(void);
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 7510383d78a6..47426df69875 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -144,6 +144,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val);
extern unsigned long kvm_nvhe_sym(__icache_flags);
extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
-extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);
+extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_cpu_vl);
#endif /* __ARM64_KVM_HYP_H__ */
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index cd56acd9a842..6fc0cf42fca3 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -134,7 +134,7 @@ static inline size_t pkvm_host_sve_state_size(void)
return 0;
return size_add(sizeof(struct cpu_sve_state),
- SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_vl)));
+ SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_cpu_vl)));
}
#endif /* __ARM64_KVM_PKVM_H__ */
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index bd8f671e848c..d232775b72c9 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -90,8 +90,8 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt;
hyp_vcpu->vcpu.arch.sve_state = kern_hyp_va(host_vcpu->arch.sve_state);
- /* Limit guest vector length to the maximum supported by the host. */
- hyp_vcpu->vcpu.arch.sve_max_vl = min(host_vcpu->arch.sve_max_vl, kvm_host_sve_max_vl);
+ /* Limit guest vector length to the maximum supported by any CPU. */
+ hyp_vcpu->vcpu.arch.sve_max_vl = min(host_vcpu->arch.sve_max_vl, kvm_host_sve_max_cpu_vl);
hyp_vcpu->vcpu.arch.hw_mmu = host_vcpu->arch.hw_mmu;
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 95cf18574251..08e825de09d1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -18,7 +18,7 @@ unsigned long __icache_flags;
/* Used by kvm_get_vttbr(). */
unsigned int kvm_arm_vmid_bits;
-unsigned int kvm_host_sve_max_vl;
+unsigned int kvm_host_sve_max_cpu_vl;
/*
* Set trap register values based on features in ID_AA64PFR0.
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 3fc8ca164dbe..59cccb477cf3 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -32,7 +32,7 @@
/* Maximum phys_shift supported for any VM on this host */
static u32 __ro_after_init kvm_ipa_limit;
-unsigned int __ro_after_init kvm_host_sve_max_vl;
+unsigned int __ro_after_init kvm_host_sve_max_cpu_vl;
/*
* ARMv8 Reset Values
@@ -52,8 +52,8 @@ int __init kvm_arm_init_sve(void)
{
if (system_supports_sve()) {
kvm_sve_max_vl = sve_max_virtualisable_vl();
- kvm_host_sve_max_vl = sve_max_vl();
- kvm_nvhe_sym(kvm_host_sve_max_vl) = kvm_host_sve_max_vl;
+ kvm_host_sve_max_cpu_vl = sve_max_cpu_vl();
+ kvm_nvhe_sym(kvm_host_sve_max_cpu_vl) = kvm_host_sve_max_cpu_vl;
/*
* The get_sve_reg()/set_sve_reg() ioctl interface will need
--
2.39.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 11+ messages in thread