static int compat_vfp_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { struct user_fpsimd_state *uregs; compat_ulong_t fpscr; int ret; if (pos + count > VFP_STATE_SIZE) return -EIO; uregs = &target->thread.fpsimd_state.user_fpsimd; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, VFP_STATE_SIZE - sizeof(compat_ulong_t)); if (count && !ret) { ret = get_user(fpscr, (compat_ulong_t *)ubuf); uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK; uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK; } fpsimd_flush_task_state(target); return ret; }
void fpsimd_flush_thread(void) { preempt_disable(); memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state)); fpsimd_flush_task_state(current); set_thread_flag(TIF_FOREIGN_FPSTATE); preempt_enable(); }
void fpsimd_flush_thread(void) { if (!system_supports_fpsimd()) return; preempt_disable(); memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state)); fpsimd_flush_task_state(current); set_thread_flag(TIF_FOREIGN_FPSTATE); preempt_enable(); }
static int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { int ret; struct user_fpsimd_state newstate; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1); if (ret) return ret; target->thread.fpsimd_state.user_fpsimd = newstate; fpsimd_flush_task_state(target); return ret; }
int sve_set_vector_length(struct task_struct *task, unsigned long vl, unsigned long flags) { if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT | PR_SVE_SET_VL_ONEXEC)) return -EINVAL; if (!sve_vl_valid(vl)) return -EINVAL; /* * Clamp to the maximum vector length that VL-agnostic SVE code can * work with. A flag may be assigned in the future to allow setting * of larger vector lengths without confusing older software. */ if (vl > SVE_VL_ARCH_MAX) vl = SVE_VL_ARCH_MAX; vl = find_supported_vector_length(vl); if (flags & (PR_SVE_VL_INHERIT | PR_SVE_SET_VL_ONEXEC)) task->thread.sve_vl_onexec = vl; else /* Reset VL to system default on next exec: */ task->thread.sve_vl_onexec = 0; /* Only actually set the VL if not deferred: */ if (flags & PR_SVE_SET_VL_ONEXEC) goto out; if (vl == task->thread.sve_vl) goto out; /* * To ensure the FPSIMD bits of the SVE vector registers are preserved, * write any live register state back to task_struct, and convert to a * non-SVE thread. */ if (task == current) { local_bh_disable(); fpsimd_save(); set_thread_flag(TIF_FOREIGN_FPSTATE); } fpsimd_flush_task_state(task); if (test_and_clear_tsk_thread_flag(task, TIF_SVE)) sve_to_fpsimd(task); if (task == current) local_bh_enable(); /* * Force reallocation of task SVE state to the correct size * on next use: */ sve_free(task); task->thread.sve_vl = vl; out: update_tsk_thread_flag(task, TIF_SVE_VL_INHERIT, flags & PR_SVE_VL_INHERIT); return 0; }
int copy_thread(unsigned long clone_flags, unsigned long stack_start, unsigned long stk_sz, struct task_struct *p) { struct pt_regs *childregs = task_pt_regs(p); memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); /* * Unalias p->thread.sve_state (if any) from the parent task * and disable discard SVE state for p: */ clear_tsk_thread_flag(p, TIF_SVE); p->thread.sve_state = NULL; /* * In case p was allocated the same task_struct pointer as some * other recently-exited task, make sure p is disassociated from * any cpu that may have run that now-exited task recently. * Otherwise we could erroneously skip reloading the FPSIMD * registers for p. */ fpsimd_flush_task_state(p); if (likely(!(p->flags & PF_KTHREAD))) { *childregs = *current_pt_regs(); childregs->regs[0] = 0; /* * Read the current TLS pointer from tpidr_el0 as it may be * out-of-sync with the saved value. */ *task_user_tls(p) = read_sysreg(tpidr_el0); if (stack_start) { if (is_compat_thread(task_thread_info(p))) childregs->compat_sp = stack_start; else childregs->sp = stack_start; } /* * If a TLS pointer was passed to clone (4th argument), use it * for the new thread. */ if (clone_flags & CLONE_SETTLS) p->thread.uw.tp_value = childregs->regs[3]; } else { memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h; if (IS_ENABLED(CONFIG_ARM64_UAO) && cpus_have_const_cap(ARM64_HAS_UAO)) childregs->pstate |= PSR_UAO_BIT; if (arm64_get_ssbd_state() == ARM64_SSBD_FORCE_DISABLE) childregs->pstate |= PSR_SSBS_BIT; if (system_uses_irq_prio_masking()) childregs->pmr_save = GIC_PRIO_IRQON; p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; } p->thread.cpu_context.pc = (unsigned long)ret_from_fork; p->thread.cpu_context.sp = (unsigned long)childregs; ptrace_hw_copy_thread(p); return 0; }