2125 lines · 58.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * FP/SIMD context switching and fault handling * * Copyright (C) 2012 ARM Ltd. * Author: Catalin Marinas <catalin.marinas@arm.com> */ #include <linux/bitmap.h>#include <linux/bitops.h>#include <linux/bottom_half.h>#include <linux/bug.h>#include <linux/cache.h>#include <linux/compat.h>#include <linux/compiler.h>#include <linux/cpu.h>#include <linux/cpu_pm.h>#include <linux/cpumask.h>#include <linux/ctype.h>#include <linux/kernel.h>#include <linux/linkage.h>#include <linux/irqflags.h>#include <linux/init.h>#include <linux/percpu.h>#include <linux/prctl.h>#include <linux/preempt.h>#include <linux/ptrace.h>#include <linux/sched/signal.h>#include <linux/sched/task_stack.h>#include <linux/signal.h>#include <linux/slab.h>#include <linux/smp.h>#include <linux/stddef.h>#include <linux/sysctl.h>#include <linux/swab.h> #include <asm/esr.h>#include <asm/exception.h>#include <asm/fpsimd.h>#include <asm/cpufeature.h>#include <asm/cputype.h>#include <asm/neon.h>#include <asm/processor.h>#include <asm/simd.h>#include <asm/sigcontext.h>#include <asm/sysreg.h>#include <asm/traps.h>#include <asm/virt.h> #define FPEXC_IOF	(1 << 0)#define FPEXC_DZF	(1 << 1)#define FPEXC_OFF	(1 << 2)#define FPEXC_UFF	(1 << 3)#define FPEXC_IXF	(1 << 4)#define FPEXC_IDF	(1 << 7) /* * (Note: in this discussion, statements about FPSIMD apply equally to SVE.) * * In order to reduce the number of times the FPSIMD state is needlessly saved * and restored, we need to keep track of two things: * (a) for each task, we need to remember which CPU was the last one to have *     the task's FPSIMD state loaded into its FPSIMD registers; * (b) for each CPU, we need to remember which task's userland FPSIMD state has *     been loaded into its FPSIMD registers most recently, or whether it has *     been used to perform kernel mode NEON in the meantime. * * For (a), we add a fpsimd_cpu field to thread_struct, which gets updated to * the id of the current CPU every time the state is loaded onto a CPU. For (b), * we add the per-cpu variable 'fpsimd_last_state' (below), which contains the * address of the userland FPSIMD state of the task that was loaded onto the CPU * the most recently, or NULL if kernel mode NEON has been performed after that. * * With this in place, we no longer have to restore the next FPSIMD state right * when switching between tasks. Instead, we can defer this check to userland * resume, at which time we verify whether the CPU's fpsimd_last_state and the * task's fpsimd_cpu are still mutually in sync. If this is the case, we * can omit the FPSIMD restore. * * As an optimization, we use the thread_info flag TIF_FOREIGN_FPSTATE to * indicate whether or not the userland FPSIMD state of the current task is * present in the registers. The flag is set unless the FPSIMD registers of this * CPU currently contain the most recent userland FPSIMD state of the current * task. If the task is behaving as a VMM, then this is will be managed by * KVM which will clear it to indicate that the vcpu FPSIMD state is currently * loaded on the CPU, allowing the state to be saved if a FPSIMD-aware * softirq kicks in. Upon vcpu_put(), KVM will save the vcpu FP state and * flag the register state as invalid. * * In order to allow softirq handlers to use FPSIMD, kernel_neon_begin() may be * called from softirq context, which will save the task's FPSIMD context back * to task_struct. To prevent this from racing with the manipulation of the * task's FPSIMD state from task context and thereby corrupting the state, it * is necessary to protect any manipulation of a task's fpsimd_state or * TIF_FOREIGN_FPSTATE flag with get_cpu_fpsimd_context(), which will suspend * softirq servicing entirely until put_cpu_fpsimd_context() is called. * * For a certain task, the sequence may look something like this: * - the task gets scheduled in; if both the task's fpsimd_cpu field *   contains the id of the current CPU, and the CPU's fpsimd_last_state per-cpu *   variable points to the task's fpsimd_state, the TIF_FOREIGN_FPSTATE flag is *   cleared, otherwise it is set; * * - the task returns to userland; if TIF_FOREIGN_FPSTATE is set, the task's *   userland FPSIMD state is copied from memory to the registers, the task's *   fpsimd_cpu field is set to the id of the current CPU, the current *   CPU's fpsimd_last_state pointer is set to this task's fpsimd_state and the *   TIF_FOREIGN_FPSTATE flag is cleared; * * - the task executes an ordinary syscall; upon return to userland, the *   TIF_FOREIGN_FPSTATE flag will still be cleared, so no FPSIMD state is *   restored; * * - the task executes a syscall which executes some NEON instructions; this is *   preceded by a call to kernel_neon_begin(), which copies the task's FPSIMD *   register contents to memory, clears the fpsimd_last_state per-cpu variable *   and sets the TIF_FOREIGN_FPSTATE flag; * * - the task gets preempted after kernel_neon_end() is called; as we have not *   returned from the 2nd syscall yet, TIF_FOREIGN_FPSTATE is still set so *   whatever is in the FPSIMD registers is not saved to memory, but discarded. */ DEFINE_PER_CPU(struct cpu_fp_state, fpsimd_last_state); __ro_after_init struct vl_info vl_info[ARM64_VEC_MAX] = {#ifdef CONFIG_ARM64_SVE	[ARM64_VEC_SVE] = {		.type			= ARM64_VEC_SVE,		.name			= "SVE",		.min_vl			= SVE_VL_MIN,		.max_vl			= SVE_VL_MIN,		.max_virtualisable_vl	= SVE_VL_MIN,	},#endif#ifdef CONFIG_ARM64_SME	[ARM64_VEC_SME] = {		.type			= ARM64_VEC_SME,		.name			= "SME",	},#endif}; static unsigned int vec_vl_inherit_flag(enum vec_type type){	switch (type) {	case ARM64_VEC_SVE:		return TIF_SVE_VL_INHERIT;	case ARM64_VEC_SME:		return TIF_SME_VL_INHERIT;	default:		WARN_ON_ONCE(1);		return 0;	}} struct vl_config {	int __default_vl;		/* Default VL for tasks */}; static struct vl_config vl_config[ARM64_VEC_MAX]; static inline int get_default_vl(enum vec_type type){	return READ_ONCE(vl_config[type].__default_vl);} #ifdef CONFIG_ARM64_SVE static inline int get_sve_default_vl(void){	return get_default_vl(ARM64_VEC_SVE);} static inline void set_default_vl(enum vec_type type, int val){	WRITE_ONCE(vl_config[type].__default_vl, val);} static inline void set_sve_default_vl(int val){	set_default_vl(ARM64_VEC_SVE, val);} #endif /* ! CONFIG_ARM64_SVE */ #ifdef CONFIG_ARM64_SME static int get_sme_default_vl(void){	return get_default_vl(ARM64_VEC_SME);} static void set_sme_default_vl(int val){	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 static void fpsimd_bind_task_to_cpu(void); /* * Claim ownership of the CPU FPSIMD context for use by the calling context. * * The caller may freely manipulate the FPSIMD context metadata until * put_cpu_fpsimd_context() is called. * * On RT kernels local_bh_disable() is not sufficient because it only * serializes soft interrupt related sections via a local lock, but stays * preemptible. Disabling preemption is the right choice here as bottom * half processing is always in thread context on RT kernels so it * implicitly prevents bottom half processing as well. */static void get_cpu_fpsimd_context(void){	if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {		/*		 * The softirq subsystem lacks a true unmask/mask API, and		 * re-enabling softirq processing using local_bh_enable() will		 * not only unmask softirqs, it will also result in immediate		 * delivery of any pending softirqs.		 * This is undesirable when running with IRQs disabled, but in		 * that case, there is no need to mask softirqs in the first		 * place, so only bother doing so when IRQs are enabled.		 */		if (!irqs_disabled())			local_bh_disable();	} else {		preempt_disable();	}} /* * Release the CPU FPSIMD context. * * Must be called from a context in which get_cpu_fpsimd_context() was * previously called, with no call to put_cpu_fpsimd_context() in the * meantime. */static void put_cpu_fpsimd_context(void){	if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {		if (!irqs_disabled())			local_bh_enable();	} else {		preempt_enable();	}} unsigned int task_get_vl(const struct task_struct *task, enum vec_type type){	return task->thread.vl[type];} void task_set_vl(struct task_struct *task, enum vec_type type,		 unsigned long vl){	task->thread.vl[type] = vl;} unsigned int task_get_vl_onexec(const struct task_struct *task,				enum vec_type type){	return task->thread.vl_onexec[type];} void task_set_vl_onexec(struct task_struct *task, enum vec_type type,			unsigned long vl){	task->thread.vl_onexec[type] = vl;} /* * TIF_SME controls whether a task can use SME without trapping while * in userspace, when TIF_SME is set then we must have storage * allocated in sve_state and sme_state to store the contents of both ZA * and the SVE registers for both streaming and non-streaming modes. * * If both SVCR.ZA and SVCR.SM are disabled then at any point we * may disable TIF_SME and reenable traps. */  /* * TIF_SVE controls whether a task can use SVE without trapping while * in userspace, and also (together with TIF_SME) the way a task's * FPSIMD/SVE state is stored in thread_struct. * * The kernel uses this flag to track whether a user task is actively * using SVE, and therefore whether full SVE register state needs to * be tracked.  If not, the cheaper FPSIMD context handling code can * be used instead of the more costly SVE equivalents. * *  * TIF_SVE or SVCR.SM set: * *    The task can execute SVE instructions while in userspace without *    trapping to the kernel. * *    During any syscall, the kernel may optionally clear TIF_SVE and *    discard the vector state except for the FPSIMD subset. * *  * TIF_SVE clear: * *    An attempt by the user task to execute an SVE instruction causes *    do_sve_acc() to be called, which does some preparation and then *    sets TIF_SVE. * * During any syscall, the kernel may optionally clear TIF_SVE and * discard the vector state except for the FPSIMD subset. * * The data will be stored in one of two formats: * *  * FPSIMD only - FP_STATE_FPSIMD: * *    When the FPSIMD only state stored task->thread.fp_type is set to *    FP_STATE_FPSIMD, the FPSIMD registers V0-V31 are encoded in *    task->thread.uw.fpsimd_state; bits [max : 128] for each of Z0-Z31 are *    logically zero but not stored anywhere; P0-P15 and FFR are not *    stored and have unspecified values from userspace's point of *    view.  For hygiene purposes, the kernel zeroes them on next use, *    but userspace is discouraged from relying on this. * *    task->thread.sve_state does not need to be non-NULL, valid or any *    particular size: it must not be dereferenced and any data stored *    there should be considered stale and not referenced. * *  * SVE state - FP_STATE_SVE: * *    When the full SVE state is stored task->thread.fp_type is set to *    FP_STATE_SVE and Z0-Z31 (incorporating Vn in bits[127:0] or the *    corresponding Zn), P0-P15 and FFR are encoded in in *    task->thread.sve_state, formatted appropriately for vector *    length task->thread.sve_vl or, if SVCR.SM is set, *    task->thread.sme_vl. The storage for the vector registers in *    task->thread.uw.fpsimd_state should be ignored. * *    task->thread.sve_state must point to a valid buffer at least *    sve_state_size(task) bytes in size. The data stored in *    task->thread.uw.fpsimd_state.vregs should be considered stale *    and not referenced. * *  * FPSR and FPCR are always stored in task->thread.uw.fpsimd_state *    irrespective of whether TIF_SVE is clear or set, since these are *    not vector length dependent. */ /* * Update current's FPSIMD/SVE registers from thread_struct. * * This function should be called only when the FPSIMD/SVE state in * thread_struct is known to be up to date, when preparing to enter * userspace. */static void task_fpsimd_load(void){	bool restore_sve_regs = false;	bool restore_ffr; 	WARN_ON(!system_supports_fpsimd());	WARN_ON(preemptible());	WARN_ON(test_thread_flag(TIF_KERNEL_FPSTATE)); 	if (system_supports_sve() || system_supports_sme()) {		switch (current->thread.fp_type) {		case FP_STATE_FPSIMD:			/* Stop tracking SVE for this task until next use. */			clear_thread_flag(TIF_SVE);			break;		case FP_STATE_SVE:			if (!thread_sm_enabled(&current->thread))				WARN_ON_ONCE(!test_and_set_thread_flag(TIF_SVE)); 			if (test_thread_flag(TIF_SVE)) {				unsigned long vq = sve_vq_from_vl(task_get_sve_vl(current));				sysreg_clear_set_s(SYS_ZCR_EL1, ZCR_ELx_LEN, vq - 1);			} 			restore_sve_regs = true;			restore_ffr = true;			break;		default:			/*			 * This indicates either a bug in			 * fpsimd_save_user_state() or memory corruption, we			 * should always record an explicit format			 * when we save. We always at least have the			 * memory allocated for FPSIMD registers so			 * try that and hope for the best.			 */			WARN_ON_ONCE(1);			clear_thread_flag(TIF_SVE);			break;		}	} 	/* Restore SME, override SVE register configuration if needed */	if (system_supports_sme()) {		unsigned long sme_vl = task_get_sme_vl(current); 		/* Ensure VL is set up for restoring data */		if (test_thread_flag(TIF_SME)) {			unsigned long vq = sve_vq_from_vl(sme_vl);			sysreg_clear_set_s(SYS_SMCR_EL1, SMCR_ELx_LEN, vq - 1);		} 		write_sysreg_s(current->thread.svcr, SYS_SVCR); 		if (thread_za_enabled(&current->thread))			sme_load_state(current->thread.sme_state,				       system_supports_sme2()); 		if (thread_sm_enabled(&current->thread))			restore_ffr = system_supports_fa64();	} 	if (system_supports_fpmr())		write_sysreg_s(current->thread.uw.fpmr, SYS_FPMR); 	if (restore_sve_regs) {		WARN_ON_ONCE(current->thread.fp_type != FP_STATE_SVE);		sve_load_state(current->thread.sve_state, restore_ffr);		fpsimd_load_common(&current->thread.uw.fpsimd_state);	} else {		WARN_ON_ONCE(current->thread.fp_type != FP_STATE_FPSIMD);		fpsimd_load_state(&current->thread.uw.fpsimd_state);	}} /* * Ensure FPSIMD/SVE storage in memory for the loaded context is up to * date with respect to the CPU registers. Note carefully that the * current context is the context last bound to the CPU stored in * last, if KVM is involved this may be the guest VM context rather * than the host thread for the VM pointed to by current. This means * that we must always reference the state storage via last rather * than via current, if we are saving KVM state then it will have * ensured that the type of registers to save is set in last->to_save. */static void fpsimd_save_user_state(void){	struct cpu_fp_state const *last =		this_cpu_ptr(&fpsimd_last_state);	/* set by fpsimd_bind_task_to_cpu() or fpsimd_bind_state_to_cpu() */	bool save_sve_regs = false;	bool save_ffr;	unsigned int vl; 	WARN_ON(!system_supports_fpsimd());	WARN_ON(preemptible()); 	if (test_thread_flag(TIF_FOREIGN_FPSTATE))		return; 	if (system_supports_fpmr())		*(last->fpmr) = read_sysreg_s(SYS_FPMR); 	/*	 * Save SVE state if it is live.	 *	 * The syscall ABI discards live SVE state at syscall entry. When	 * entering a syscall, fpsimd_syscall_enter() sets to_save to	 * FP_STATE_FPSIMD to allow the SVE state to be lazily discarded until	 * either new SVE state is loaded+bound or fpsimd_syscall_exit() is	 * called prior to a return to userspace.	 */	if ((last->to_save == FP_STATE_CURRENT && test_thread_flag(TIF_SVE)) ||	    last->to_save == FP_STATE_SVE) {		save_sve_regs = true;		save_ffr = true;		vl = last->sve_vl;	} 	if (system_supports_sme()) {		u64 *svcr = last->svcr; 		*svcr = read_sysreg_s(SYS_SVCR); 		if (*svcr & SVCR_ZA_MASK)			sme_save_state(last->sme_state,				       system_supports_sme2()); 		/* If we are in streaming mode override regular SVE. */		if (*svcr & SVCR_SM_MASK) {			save_sve_regs = true;			save_ffr = system_supports_fa64();			vl = last->sme_vl;		}	} 	if (IS_ENABLED(CONFIG_ARM64_SVE) && save_sve_regs) {		/* Get the configured VL from RDVL, will account for SM */		if (WARN_ON(sve_get_vl() != vl)) {			/*

Lines 1–500 of 2125.