int __ro_after_init sve_max_vl = -1;
 /* Set of available vector lengths, as vq_to_bit(vq): */
 static __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+static void __percpu *efi_sve_state;
 
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declaration for code that will be optimised out: */
 extern __ro_after_init DECLARE_BITMAP(sve_vq_map, SVE_VQ_MAX);
+extern void __percpu *efi_sve_state;
 
 #endif /* ! CONFIG_ARM64_SVE */
 
        return ret;
 }
 
+static void __init sve_efi_setup(void)
+{
+       if (!IS_ENABLED(CONFIG_EFI))
+               return;
+
+       /*
+        * alloc_percpu() warns and prints a backtrace if this goes wrong.
+        * This is evidence of a crippled system and we are returning void,
+        * so no attempt is made to handle this situation here.
+        */
+       if (!sve_vl_valid(sve_max_vl))
+               goto fail;
+
+       efi_sve_state = __alloc_percpu(
+               SVE_SIG_REGS_SIZE(sve_vq_from_vl(sve_max_vl)), SVE_VQ_BYTES);
+       if (!efi_sve_state)
+               goto fail;
+
+       return;
+
+fail:
+       panic("Cannot allocate percpu memory for EFI SVE save/restore");
+}
+
 /*
  * Enable SVE for EL1.
  * Intended for use by the cpufeatures code during CPU boot.
                sve_max_vl);
        pr_info("SVE: default vector length %u bytes per vector\n",
                sve_default_vl);
+
+       sve_efi_setup();
 }
 
 /*
 
 static DEFINE_PER_CPU(struct fpsimd_state, efi_fpsimd_state);
 static DEFINE_PER_CPU(bool, efi_fpsimd_state_used);
+static DEFINE_PER_CPU(bool, efi_sve_state_used);
 
 /*
  * EFI runtime services support functions
 
        WARN_ON(preemptible());
 
-       if (may_use_simd())
+       if (may_use_simd()) {
                kernel_neon_begin();
-       else {
-               fpsimd_save_state(this_cpu_ptr(&efi_fpsimd_state));
+       } else {
+               /*
+                * If !efi_sve_state, SVE can't be in use yet and doesn't need
+                * preserving:
+                */
+               if (system_supports_sve() && likely(efi_sve_state)) {
+                       char *sve_state = this_cpu_ptr(efi_sve_state);
+
+                       __this_cpu_write(efi_sve_state_used, true);
+
+                       sve_save_state(sve_state + sve_ffr_offset(sve_max_vl),
+                                      &this_cpu_ptr(&efi_fpsimd_state)->fpsr);
+               } else {
+                       fpsimd_save_state(this_cpu_ptr(&efi_fpsimd_state));
+               }
+
                __this_cpu_write(efi_fpsimd_state_used, true);
        }
 }
        if (!system_supports_fpsimd())
                return;
 
-       if (__this_cpu_xchg(efi_fpsimd_state_used, false))
-               fpsimd_load_state(this_cpu_ptr(&efi_fpsimd_state));
-       else
+       if (!__this_cpu_xchg(efi_fpsimd_state_used, false)) {
                kernel_neon_end();
+       } else {
+               if (system_supports_sve() &&
+                   likely(__this_cpu_read(efi_sve_state_used))) {
+                       char const *sve_state = this_cpu_ptr(efi_sve_state);
+
+                       sve_load_state(sve_state + sve_ffr_offset(sve_max_vl),
+                                      &this_cpu_ptr(&efi_fpsimd_state)->fpsr,
+                                      sve_vq_from_vl(sve_get_vl()) - 1);
+
+                       __this_cpu_write(efi_sve_state_used, false);
+               } else {
+                       fpsimd_load_state(this_cpu_ptr(&efi_fpsimd_state));
+               }
+       }
 }
 
 #endif /* CONFIG_EFI */