/* * Save the userland FPSIMD state of 'current' to memory, but only if the state * currently held in the registers does in fact belong to 'current' */ void fpsimd_preserve_current_state(void) { preempt_disable(); if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); preempt_enable(); }
void fpsimd_thread_switch(struct task_struct *next) { /* * Save the current FPSIMD state to memory, but only if whatever is in * the registers is in fact the most recent userland FPSIMD state of * 'current'. */ if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); if (next->mm) { /* * If we are switching to a task whose most recent userland * FPSIMD state is already in the registers of *this* cpu, * we can skip loading the state from memory. Otherwise, set * the TIF_FOREIGN_FPSTATE flag so the state will be loaded * upon the next return to userland. */ struct fpsimd_state *st = &next->thread.fpsimd_state; if (__this_cpu_read(fpsimd_last_state) == st && st->cpu == smp_processor_id()) clear_ti_thread_flag(task_thread_info(next), TIF_FOREIGN_FPSTATE); else set_ti_thread_flag(task_thread_info(next), TIF_FOREIGN_FPSTATE); } }
void fpsimd_thread_switch(struct task_struct *next) { /* check if not kernel threads */ if (current->mm) fpsimd_save_state(¤t->thread.fpsimd_state); if (next->mm) fpsimd_load_state(&next->thread.fpsimd_state); }
/* * Kernel-side NEON support functions */ void kernel_neon_begin(void) { /* Avoid using the NEON in interrupt context */ BUG_ON(in_interrupt()); preempt_disable(); if (current->mm) fpsimd_save_state(¤t->thread.fpsimd_state); }
/* * Save the userland FPSIMD state of 'current' to memory, but only if the state * currently held in the registers does in fact belong to 'current' */ void fpsimd_preserve_current_state(void) { if (!system_supports_fpsimd()) return; preempt_disable(); if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); preempt_enable(); }
static int fpsimd_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v) { switch (cmd) { case CPU_PM_ENTER: if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); break; case CPU_PM_EXIT: if (current->mm) set_thread_flag(TIF_FOREIGN_FPSTATE); break; case CPU_PM_ENTER_FAILED: default: return NOTIFY_DONE; } return NOTIFY_OK; }
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) { struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state; int err; /* dump the hardware registers to the fpsimd_state structure */ fpsimd_save_state(fpsimd); /* copy the FP and status/control registers */ err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs)); __put_user_error(fpsimd->fpsr, &ctx->fpsr, err); __put_user_error(fpsimd->fpcr, &ctx->fpcr, err); /* copy the magic/size information */ __put_user_error(FPSIMD_MAGIC, &ctx->head.magic, err); __put_user_error(sizeof(struct fpsimd_context), &ctx->head.size, err); return err ? -EFAULT : 0; }
/* * Kernel-side NEON support functions */ void kernel_neon_begin_partial(u32 num_regs) { if (in_interrupt()) { struct fpsimd_partial_state *s = this_cpu_ptr( in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate); BUG_ON(num_regs > 32); fpsimd_save_partial_state(s, roundup(num_regs, 2)); } else { /* * Save the userland FPSIMD state if we have one and if we * haven't done so already. Clear fpsimd_last_state to indicate * that there is no longer userland FPSIMD state in the * registers. */ preempt_disable(); if (current->mm) fpsimd_save_state(¤t->thread.fpsimd_state); } }
/* * Ensure FPSIMD/SVE storage in memory for the loaded context is up to * date with respect to the CPU registers. * * Softirqs (and preemption) must be disabled. */ void fpsimd_save(void) { struct user_fpsimd_state *st = __this_cpu_read(fpsimd_last_state.st); /* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */ WARN_ON(!in_softirq() && !irqs_disabled()); if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) { if (system_supports_sve() && test_thread_flag(TIF_SVE)) { if (WARN_ON(sve_get_vl() != current->thread.sve_vl)) { /* * Can't save the user regs, so current would * re-enter user with corrupt state. * There's no way to recover, so kill it: */ force_signal_inject(SIGKILL, SI_KERNEL, 0); return; } sve_save_state(sve_pffr(¤t->thread), &st->fpsr); } else fpsimd_save_state(st); } }
/* * Kernel-side NEON support functions */ void kernel_neon_begin_partial(u32 num_regs) { if (WARN_ON(!system_supports_fpsimd())) return; if (in_interrupt()) { struct fpsimd_partial_state *s = this_cpu_ptr( in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate); BUG_ON(num_regs > 32); fpsimd_save_partial_state(s, roundup(num_regs, 2)); } else { /* * Save the userland FPSIMD state if we have one and if we * haven't done so already. Clear fpsimd_last_state to indicate * that there is no longer userland FPSIMD state in the * registers. */ preempt_disable(); if (current->mm && !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); this_cpu_write(fpsimd_last_state, NULL); } }