val = read_sysreg(cpacr_el1);
        val |= CPACR_EL1_TTA;
        val &= ~CPACR_EL1_ZEN;
-       if (!update_fp_enabled(vcpu)) {
+       if (update_fp_enabled(vcpu)) {
+               if (vcpu_has_sve(vcpu))
+                       val |= CPACR_EL1_ZEN;
+       } else {
                val &= ~CPACR_EL1_FPEN;
                __activate_traps_fpsimd32(vcpu);
        }
        return true;
 }
 
-static bool __hyp_text __hyp_switch_fpsimd(struct kvm_vcpu *vcpu)
+/* Check for an FPSIMD/SVE trap and handle as appropriate */
+static bool __hyp_text __hyp_handle_fpsimd(struct kvm_vcpu *vcpu)
 {
-       struct user_fpsimd_state *host_fpsimd = vcpu->arch.host_fpsimd_state;
+       bool vhe, sve_guest, sve_host;
+       u8 hsr_ec;
 
-       if (has_vhe())
-               write_sysreg(read_sysreg(cpacr_el1) | CPACR_EL1_FPEN,
-                            cpacr_el1);
-       else
+       if (!system_supports_fpsimd())
+               return false;
+
+       if (system_supports_sve()) {
+               sve_guest = vcpu_has_sve(vcpu);
+               sve_host = vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE;
+               vhe = true;
+       } else {
+               sve_guest = false;
+               sve_host = false;
+               vhe = has_vhe();
+       }
+
+       hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+       if (hsr_ec != ESR_ELx_EC_FP_ASIMD &&
+           hsr_ec != ESR_ELx_EC_SVE)
+               return false;
+
+       /* Don't handle SVE traps for non-SVE vcpus here: */
+       if (!sve_guest)
+               if (hsr_ec != ESR_ELx_EC_FP_ASIMD)
+                       return false;
+
+       /* Valid trap.  Switch the context: */
+
+       if (vhe) {
+               u64 reg = read_sysreg(cpacr_el1) | CPACR_EL1_FPEN;
+
+               if (sve_guest)
+                       reg |= CPACR_EL1_ZEN;
+
+               write_sysreg(reg, cpacr_el1);
+       } else {
                write_sysreg(read_sysreg(cptr_el2) & ~(u64)CPTR_EL2_TFP,
                             cptr_el2);
+       }
 
        isb();
 
                 * In the SVE case, VHE is assumed: it is enforced by
                 * Kconfig and kvm_arch_init().
                 */
-               if (system_supports_sve() &&
-                   (vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE)) {
+               if (sve_host) {
                        struct thread_struct *thread = container_of(
-                               host_fpsimd,
+                               vcpu->arch.host_fpsimd_state,
                                struct thread_struct, uw.fpsimd_state);
 
-                       sve_save_state(sve_pffr(thread), &host_fpsimd->fpsr);
+                       sve_save_state(sve_pffr(thread),
+                                      &vcpu->arch.host_fpsimd_state->fpsr);
                } else {
-                       __fpsimd_save_state(host_fpsimd);
+                       __fpsimd_save_state(vcpu->arch.host_fpsimd_state);
                }
 
                vcpu->arch.flags &= ~KVM_ARM64_FP_HOST;
        }
 
-       __fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
-
-       if (vcpu_has_sve(vcpu))
+       if (sve_guest) {
+               sve_load_state(vcpu_sve_pffr(vcpu),
+                              &vcpu->arch.ctxt.gp_regs.fp_regs.fpsr,
+                              sve_vq_from_vl(vcpu->arch.sve_max_vl) - 1);
                write_sysreg_s(vcpu->arch.ctxt.sys_regs[ZCR_EL1], SYS_ZCR_EL12);
+       } else {
+               __fpsimd_restore_state(&vcpu->arch.ctxt.gp_regs.fp_regs);
+       }
 
        /* Skip restoring fpexc32 for AArch64 guests */
        if (!(read_sysreg(hcr_el2) & HCR_RW))
         * and restore the guest context lazily.
         * If FP/SIMD is not implemented, handle the trap and inject an
         * undefined instruction exception to the guest.
+        * Similarly for trapped SVE accesses.
         */
-       if (system_supports_fpsimd() &&
-           kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_FP_ASIMD)
-               return __hyp_switch_fpsimd(vcpu);
+       if (__hyp_handle_fpsimd(vcpu))
+               return true;
 
        if (!__populate_fault_info(vcpu))
                return true;