return vq_available(ARM64_VEC_SVE, vq);
 }
 
+size_t sve_state_size(struct task_struct const *task);
+
 #else /* ! CONFIG_ARM64_SVE */
 
 static inline void sve_alloc(struct task_struct *task) { }
 static inline int vec_verify_vq_map(enum vec_type t) { return 0; }
 static inline void sve_setup(void) { }
 
+static inline size_t sve_state_size(struct task_struct const *task)
+{
+       return 0;
+}
+
 #endif /* ! CONFIG_ARM64_SVE */
 
 #ifdef CONFIG_ARM64_SME
 
+static inline void sme_user_disable(void)
+{
+       sysreg_clear_set(cpacr_el1, CPACR_EL1_SMEN_EL0EN, 0);
+}
+
+static inline void sme_user_enable(void)
+{
+       sysreg_clear_set(cpacr_el1, 0, CPACR_EL1_SMEN_EL0EN);
+}
+
 static inline void sme_smstart_sm(void)
 {
        asm volatile(__msr_s(SYS_SVCR_SMSTART_SM_EL0, "xzr"));
        return vec_max_virtualisable_vl(ARM64_VEC_SME);
 }
 
+extern void sme_alloc(struct task_struct *task);
 extern unsigned int sme_get_vl(void);
 extern int sme_set_current_vl(unsigned long arg);
 extern int sme_get_current_vl(void);
 
+/*
+ * Return how many bytes of memory are required to store the full SME
+ * specific state (currently just ZA) for task, given task's currently
+ * configured vector length.
+ */
+static inline size_t za_state_size(struct task_struct const *task)
+{
+       unsigned int vl = task_get_sme_vl(task);
+
+       return ZA_SIG_REGS_SIZE(sve_vq_from_vl(vl));
+}
+
 #else
 
+static inline void sme_user_disable(void) { BUILD_BUG(); }
+static inline void sme_user_enable(void) { BUILD_BUG(); }
+
 static inline void sme_smstart_sm(void) { }
 static inline void sme_smstop_sm(void) { }
 static inline void sme_smstop(void) { }
 
+static inline void sme_alloc(struct task_struct *task) { }
 static inline void sme_setup(void) { }
 static inline unsigned int sme_get_vl(void) { return 0; }
 static inline int sme_max_vl(void) { return 0; }
 static inline int sme_set_current_vl(unsigned long arg) { return -EINVAL; }
 static inline int sme_get_current_vl(void) { return -EINVAL; }
 
+static inline size_t za_state_size(struct task_struct const *task)
+{
+       return 0;
+}
+
 #endif /* ! CONFIG_ARM64_SME */
 
 /* For use by EFI runtime services calls only */
 
        set_default_vl(ARM64_VEC_SME, val);
 }
 
+static void sme_free(struct task_struct *);
+
+#else
+
+static inline void sme_free(struct task_struct *t) { }
+
 #endif
 
 DEFINE_PER_CPU(bool, fpsimd_context_busy);
  * Return how many bytes of memory are required to store the full SVE
  * state for task, given task's currently configured vector length.
  */
-static size_t sve_state_size(struct task_struct const *task)
+size_t sve_state_size(struct task_struct const *task)
 {
        unsigned int vl = 0;
 
            thread_sm_enabled(&task->thread))
                sve_to_fpsimd(task);
 
-       if (system_supports_sme() && type == ARM64_VEC_SME)
+       if (system_supports_sme() && type == ARM64_VEC_SME) {
                task->thread.svcr &= ~(SYS_SVCR_EL0_SM_MASK |
                                       SYS_SVCR_EL0_ZA_MASK);
+               clear_thread_flag(TIF_SME);
+       }
 
        if (task == current)
                put_cpu_fpsimd_context();
 
        /*
-        * Force reallocation of task SVE state to the correct size
-        * on next use:
+        * Force reallocation of task SVE and SME state to the correct
+        * size on next use:
         */
        sve_free(task);
+       if (system_supports_sme() && type == ARM64_VEC_SME)
+               sme_free(task);
 
        task_set_vl(task, type, vl);
 
 void fpsimd_release_task(struct task_struct *dead_task)
 {
        __sve_free(dead_task);
+       sme_free(dead_task);
 }
 
 #endif /* CONFIG_ARM64_SVE */
 
 #ifdef CONFIG_ARM64_SME
 
+/* This will move to uapi/asm/sigcontext.h when signals are implemented */
+#define ZA_SIG_REGS_SIZE(vq) ((vq * __SVE_VQ_BYTES) * (vq * __SVE_VQ_BYTES))
+
+/*
+ * Ensure that task->thread.za_state is allocated and sufficiently large.
+ *
+ * This function should be used only in preparation for replacing
+ * task->thread.za_state with new data.  The memory is always zeroed
+ * here to prevent stale data from showing through: this is done in
+ * the interest of testability and predictability, the architecture
+ * guarantees that when ZA is enabled it will be zeroed.
+ */
+void sme_alloc(struct task_struct *task)
+{
+       if (task->thread.za_state) {
+               memset(task->thread.za_state, 0, za_state_size(task));
+               return;
+       }
+
+       /* This could potentially be up to 64K. */
+       task->thread.za_state =
+               kzalloc(za_state_size(task), GFP_KERNEL);
+}
+
+static void sme_free(struct task_struct *task)
+{
+       kfree(task->thread.za_state);
+       task->thread.za_state = NULL;
+}
+
 void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
 {
        /* Set priority for all PEs to architecturally defined minimum */
 
 #endif /* CONFIG_ARM64_SME */
 
+static void sve_init_regs(void)
+{
+       /*
+        * Convert the FPSIMD state to SVE, zeroing all the state that
+        * is not shared with FPSIMD. If (as is likely) the current
+        * state is live in the registers then do this there and
+        * update our metadata for the current task including
+        * disabling the trap, otherwise update our in-memory copy.
+        * We are guaranteed to not be in streaming mode, we can only
+        * take a SVE trap when not in streaming mode and we can't be
+        * in streaming mode when taking a SME trap.
+        */
+       if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
+               unsigned long vq_minus_one =
+                       sve_vq_from_vl(task_get_sve_vl(current)) - 1;
+               sve_set_vq(vq_minus_one);
+               sve_flush_live(true, vq_minus_one);
+               fpsimd_bind_task_to_cpu();
+       } else {
+               fpsimd_to_sve(current);
+       }
+}
+
 /*
  * Trapped SVE access
  *
                WARN_ON(1); /* SVE access shouldn't have trapped */
 
        /*
-        * Convert the FPSIMD state to SVE, zeroing all the state that
-        * is not shared with FPSIMD. If (as is likely) the current
-        * state is live in the registers then do this there and
-        * update our metadata for the current task including
-        * disabling the trap, otherwise update our in-memory copy.
+        * Even if the task can have used streaming mode we can only
+        * generate SVE access traps in normal SVE mode and
+        * transitioning out of streaming mode may discard any
+        * streaming mode state.  Always clear the high bits to avoid
+        * any potential errors tracking what is properly initialised.
+        */
+       sve_init_regs();
+
+       put_cpu_fpsimd_context();
+}
+
+/*
+ * Trapped SME access
+ *
+ * Storage is allocated for the full SVE and SME state, the current
+ * FPSIMD register contents are migrated to SVE if SVE is not already
+ * active, and the access trap is disabled.
+ *
+ * TIF_SME should be clear on entry: otherwise, fpsimd_restore_current_state()
+ * would have disabled the SME access trap for userspace during
+ * ret_to_user, making an SVE access trap impossible in that case.
+ */
+void do_sme_acc(unsigned int esr, struct pt_regs *regs)
+{
+       /* Even if we chose not to use SME, the hardware could still trap: */
+       if (unlikely(!system_supports_sme()) || WARN_ON(is_compat_task())) {
+               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
+               return;
+       }
+
+       /*
+        * If this not a trap due to SME being disabled then something
+        * is being used in the wrong mode, report as SIGILL.
         */
+       if (ESR_ELx_ISS(esr) != ESR_ELx_SME_ISS_SME_DISABLED) {
+               force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
+               return;
+       }
+
+       sve_alloc(current);
+       sme_alloc(current);
+       if (!current->thread.sve_state || !current->thread.za_state) {
+               force_sig(SIGKILL);
+               return;
+       }
+
+       get_cpu_fpsimd_context();
+
+       /* With TIF_SME userspace shouldn't generate any traps */
+       if (test_and_set_thread_flag(TIF_SME))
+               WARN_ON(1);
+
        if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
                unsigned long vq_minus_one =
-                       sve_vq_from_vl(task_get_sve_vl(current)) - 1;
-               sve_set_vq(vq_minus_one);
-               sve_flush_live(true, vq_minus_one);
+                       sve_vq_from_vl(task_get_sme_vl(current)) - 1;
+               sme_set_vq(vq_minus_one);
+
                fpsimd_bind_task_to_cpu();
-       } else {
-               fpsimd_to_sve(current);
        }
 
+       /*
+        * If SVE was not already active initialise the SVE registers,
+        * any non-shared state between the streaming and regular SVE
+        * registers is architecturally guaranteed to be zeroed when
+        * we enter streaming mode.  We do not need to initialize ZA
+        * since ZA must be disabled at this point and enabling ZA is
+        * architecturally defined to zero ZA.
+        */
+       if (system_supports_sve() && !test_thread_flag(TIF_SVE))
+               sve_init_regs();
+
        put_cpu_fpsimd_context();
 }
 
                fpsimd_flush_thread_vl(ARM64_VEC_SVE);
        }
 
-       if (system_supports_sme())
+       if (system_supports_sme()) {
+               clear_thread_flag(TIF_SME);
+               sme_free(current);
                fpsimd_flush_thread_vl(ARM64_VEC_SME);
+               current->thread.svcr = 0;
+       }
 
        put_cpu_fpsimd_context();
 }
        last->svcr = ¤t->thread.svcr;
        current->thread.fpsimd_cpu = smp_processor_id();
 
+       /*
+        * Toggle SVE and SME trapping for userspace if needed, these
+        * are serialsied by ret_to_user().
+        */
+       if (system_supports_sme()) {
+               if (test_thread_flag(TIF_SME))
+                       sme_user_enable();
+               else
+                       sme_user_disable();
+       }
+
        if (system_supports_sve()) {
-               /* Toggle SVE trapping for userspace if needed */
                if (test_thread_flag(TIF_SVE))
                        sve_user_enable();
                else
                        sve_user_disable();
-
-               /* Serialised by exception return to user */
        }
 }
 
 
 
        /*
         * Detach src's sve_state (if any) from dst so that it does not
-        * get erroneously used or freed prematurely.  dst's sve_state
+        * get erroneously used or freed prematurely.  dst's copies
         * will be allocated on demand later on if dst uses SVE.
         * For consistency, also clear TIF_SVE here: this could be done
         * later in copy_process(), but to avoid tripping up future
-        * maintainers it is best not to leave TIF_SVE and sve_state in
+        * maintainers it is best not to leave TIF flags and buffers in
         * an inconsistent state, even temporarily.
         */
        dst->thread.sve_state = NULL;
        clear_tsk_thread_flag(dst, TIF_SVE);
 
-       dst->thread.svcr = 0;
+       /*
+        * In the unlikely event that we create a new thread with ZA
+        * enabled we should retain the ZA state so duplicate it here.
+        * This may be shortly freed if we exec() or if CLONE_SETTLS
+        * but it's simpler to do it here. To avoid confusing the rest
+        * of the code ensure that we have a sve_state allocated
+        * whenever za_state is allocated.
+        */
+       if (thread_za_enabled(&src->thread)) {
+               dst->thread.sve_state = kzalloc(sve_state_size(src),
+                                               GFP_KERNEL);
+               if (!dst->thread.za_state)
+                       return -ENOMEM;
+               dst->thread.za_state = kmemdup(src->thread.za_state,
+                                              za_state_size(src),
+                                              GFP_KERNEL);
+               if (!dst->thread.za_state) {
+                       kfree(dst->thread.sve_state);
+                       dst->thread.sve_state = NULL;
+                       return -ENOMEM;
+               }
+       } else {
+               dst->thread.za_state = NULL;
+               clear_tsk_thread_flag(dst, TIF_SME);
+       }
 
        /* clear any pending asynchronous tag fault raised by the parent */
        clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);