]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: pkvm: Remove struct cpu_sve_state
authorMark Rutland <mark.rutland@arm.com>
Wed, 3 Jun 2026 11:06:16 +0000 (12:06 +0100)
committerWill Deacon <will@kernel.org>
Wed, 3 Jun 2026 15:50:48 +0000 (16:50 +0100)
There's no need for struct cpu_sve_state. Code would be simpler and more
robust without it, and removing it will simplify further cleanups (e.g.
adding an opaque type for the sve register state).

Protected KVM stores most of the host's system register state in
kvm_host_data::host_ctxt, which is an instance of struct
kvm_cpu_context. As kvm_cpu_context::sys_regs[] has a slot for ZCR_EL1,
we can store the host's ZCR_EL1 there.

While kvm_cpu_context::sys_regs doesn't have slots for FPSR and FPCR,
these are usually expected to be stored in struct user_fpsimd_state.
For historical reasons, __sve_save_state and __sve_restore_state()
expect a pointer to fpsr *within* struct user_fpsimd_state, assuming the
fpcr will immediately follow, as per the order within struct
user_fpsimd_state. We currently match this ordering in struct
cpu_sve_state, but it would be simpler and more robust to use struct
user_fpsimd_state directly.

After moving ZCR_EL1, FPSR, and FPCR out of struct cpu_sve_state, all
that's left is sve_regs, which can be represented as a pointer without
need for a container struct. This is kept as a pointer to u8 (matching
the array type), as this permits the compiler to catch unbalanced
referencing/dereferencing, which is not possible for pointers to void.

Apply the above changes, and remove cpu_sve_state.

I've dropped the comment regarding buffer alignment as AFAICT this was
never necessary. The LDR/STR (vector) instructions only require this
alignment when SCTLR_ELx.A==1, which is not the case for the kernel or
hyp code. Nothing else depends on the alignment.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Vladimir Murzin <vladimir.murzin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: James Morse <james.morse@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Oliver Upton <oupton@kernel.org>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_pkvm.h
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/hyp/nvhe/hyp-main.c
arch/arm64/kvm/hyp/nvhe/setup.c

index 0595644d6a3abbdd64bdf54a8cbb5b514ffcb4a2..ae98375a8d322b15db2c78b1032534bacedc8ffd 100644 (file)
@@ -735,20 +735,6 @@ struct kvm_cpu_context {
        u64 *vncr_array;
 };
 
-struct cpu_sve_state {
-       __u64 zcr_el1;
-
-       /*
-        * Ordering is important since __sve_save_state/__sve_restore_state
-        * relies on it.
-        */
-       __u32 fpsr;
-       __u32 fpcr;
-
-       /* Must be SVE_VQ_BYTES (128 bit) aligned. */
-       __u8 sve_regs[];
-};
-
 /*
  * This structure is instantiated on a per-CPU basis, and contains
  * data that is:
@@ -774,9 +760,9 @@ struct kvm_host_data {
 
        /*
         * Hyp VA.
-        * sve_state is only used in pKVM and if system_supports_sve().
+        * sve_regs is only used in pKVM and if system_supports_sve().
         */
-       struct cpu_sve_state *sve_state;
+       u8      *sve_regs;
 
        /* Ownership of the FP regs */
        enum {
index 2954b311128c783dc42d58b9a0da49562f484ef9..74fedd9c5ff02d698bad66988c0e609b51cb8192 100644 (file)
@@ -188,8 +188,7 @@ static inline size_t pkvm_host_sve_state_size(void)
        if (!system_supports_sve())
                return 0;
 
-       return size_add(sizeof(struct cpu_sve_state),
-                       SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_vl)));
+       return SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_vl));
 }
 
 struct pkvm_mapping {
index 176cbe8baad30c60e534b9a62d4b7d835699fafd..d51586b7491584329f43734e01e95029badcaed8 100644 (file)
@@ -2495,10 +2495,10 @@ static void __init teardown_hyp_mode(void)
                        continue;
 
                if (free_sve) {
-                       struct cpu_sve_state *sve_state;
+                       u8 *sve_regs;
 
-                       sve_state = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state;
-                       free_pages((unsigned long) sve_state, pkvm_host_sve_state_order());
+                       sve_regs = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_regs;
+                       free_pages((unsigned long) sve_regs, pkvm_host_sve_state_order());
                }
 
                free_pages(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu], nvhe_percpu_order());
@@ -2623,7 +2623,7 @@ static int init_pkvm_host_sve_state(void)
                if (!page)
                        return -ENOMEM;
 
-               per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state = page_address(page);
+               per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_regs = page_address(page);
        }
 
        /*
@@ -2644,11 +2644,11 @@ static void finalize_init_hyp_mode(void)
 
        if (system_supports_sve() && is_protected_kvm_enabled()) {
                for_each_possible_cpu(cpu) {
-                       struct cpu_sve_state *sve_state;
+                       u8 *sve_regs;
 
-                       sve_state = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state;
-                       per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state =
-                               kern_hyp_va(sve_state);
+                       sve_regs = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_regs;
+                       per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_regs =
+                               kern_hyp_va(sve_regs);
                }
        }
 }
index cc4d011a2b380db52261afa27de5d01e0d0b587e..6512dd3f75ae43f15de74c4cc23c2f00b2fbb4e3 100644 (file)
@@ -484,12 +484,13 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
 
 static inline void __hyp_sve_save_host(void)
 {
-       struct cpu_sve_state *sve_state = *host_data_ptr(sve_state);
+       struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
+       u8 *sve_regs = *host_data_ptr(sve_regs);
 
-       sve_state->zcr_el1 = read_sysreg_el1(SYS_ZCR);
+       ctxt_sys_reg(hctxt, ZCR_EL1) = read_sysreg_el1(SYS_ZCR);
        write_sysreg_s(sve_vq_from_vl(kvm_host_sve_max_vl) - 1, SYS_ZCR_EL2);
-       __sve_save_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
-                        &sve_state->fpsr,
+       __sve_save_state(sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
+                        &hctxt->fp_regs.fpsr,
                         true);
 }
 
index 3b2c00ca94089c5eb9166155fbd27adacde06f98..31b0245a7e64db51d0ea513af115b959b1a2a527 100644 (file)
@@ -41,7 +41,8 @@ static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu)
 
 static void __hyp_sve_restore_host(void)
 {
-       struct cpu_sve_state *sve_state = *host_data_ptr(sve_state);
+       struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
+       u8 *sve_regs = *host_data_ptr(sve_regs);
 
        /*
         * On saving/restoring host sve state, always use the maximum VL for
@@ -53,10 +54,10 @@ static void __hyp_sve_restore_host(void)
         * need to be revisited.
         */
        write_sysreg_s(sve_vq_from_vl(kvm_host_sve_max_vl) - 1, SYS_ZCR_EL2);
-       __sve_restore_state(sve_state->sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
-                           &sve_state->fpsr,
+       __sve_restore_state(sve_regs + sve_ffr_offset(kvm_host_sve_max_vl),
+                           &hctxt->fp_regs.fpsr,
                            true);
-       write_sysreg_el1(sve_state->zcr_el1, SYS_ZCR);
+       write_sysreg_el1(ctxt_sys_reg(hctxt, ZCR_EL1), SYS_ZCR);
 }
 
 static void fpsimd_sve_flush(void)
index d8e5b563fd3d9f8c99e3baff57f6263cfb204097..39960869492006ec3cd6f8119cca6ad3f21ec906 100644 (file)
@@ -82,9 +82,9 @@ static int pkvm_create_host_sve_mappings(void)
 
        for (i = 0; i < hyp_nr_cpus; i++) {
                struct kvm_host_data *host_data = per_cpu_ptr(&kvm_host_data, i);
-               struct cpu_sve_state *sve_state = host_data->sve_state;
+               u8 *sve_regs = host_data->sve_regs;
 
-               start = kern_hyp_va(sve_state);
+               start = kern_hyp_va(sve_regs);
                end = start + PAGE_ALIGN(pkvm_host_sve_state_size());
                ret = pkvm_create_mappings(start, end, PAGE_HYP);
                if (ret)