Commit 9ea7edac authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull arm64 fixes from Will Deacon:
 "Here is a (hopefully) final round of arm64 fixes for 6.12 that address
  some user-visible floating point register corruption. Both of the
  Marks have been working on this for a couple of weeks and we've ended
  up in a position where SVE is solid but SME still has enough pending
  issues that the most pragmatic solution for the release and stable
  backports is to disable the feature. Yes, it's a shame, but the
  hardware is rare as hen's teeth at the moment and we're better off
  getting back to a known good state before fixing it all properly.
  We're also improving the selftests for 6.13 to help avoid merging
  broken code in the future.

  Anyway, the good news is that we're removing a lot more code than
  we're adding.

  Summary:

   - Fix handling of SVE traps from userspace on preemptible kernels
     when converting the saved floating point state into SVE state.

   - Remove broken support for the SMCCCv1.3 "SVE discard hint"
     optimisation.

   - Disable SME support, as the current support code suffers from
     numerous issues around signal delivery, ptrace access and
     context-switch which can lead to user-visible corruption of the
     register state"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: Kconfig: Make SME depend on BROKEN for now
  arm64: smccc: Remove broken support for SMCCCv1.3 SVE discard hint
  arm64/sve: Discard stale CPU state when handling SVE traps
parents 51b47860 81235ae0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2214,6 +2214,7 @@ config ARM64_SME
	bool "ARM Scalable Matrix Extension support"
	default y
	depends on ARM64_SVE
	depends on BROKEN
	help
	  The Scalable Matrix Extension (SME) is an extension to the AArch64
	  execution state which utilises a substantial subset of the SVE
+1 −0
Original line number Diff line number Diff line
@@ -1367,6 +1367,7 @@ static void sve_init_regs(void)
	} else {
		fpsimd_to_sve(current);
		current->thread.fp_type = FP_STATE_SVE;
		fpsimd_flush_task_state(current);
	}
}

+3 −32
Original line number Diff line number Diff line
@@ -7,48 +7,19 @@

#include <asm/asm-offsets.h>
#include <asm/assembler.h>
#include <asm/thread_info.h>

/*
 * If we have SMCCC v1.3 and (as is likely) no SVE state in
 * the registers then set the SMCCC hint bit to say there's no
 * need to preserve it.  Do this by directly adjusting the SMCCC
 * function value which is already stored in x0 ready to be called.
 */
SYM_FUNC_START(__arm_smccc_sve_check)

	ldr_l	x16, smccc_has_sve_hint
	cbz	x16, 2f

	get_current_task x16
	ldr	x16, [x16, #TSK_TI_FLAGS]
	tbnz	x16, #TIF_FOREIGN_FPSTATE, 1f	// Any live FP state?
	tbnz	x16, #TIF_SVE, 2f		// Does that state include SVE?

1:	orr	x0, x0, ARM_SMCCC_1_3_SVE_HINT

2:	ret
SYM_FUNC_END(__arm_smccc_sve_check)
EXPORT_SYMBOL(__arm_smccc_sve_check)

	.macro SMCCC instr
	stp     x29, x30, [sp, #-16]!
	mov	x29, sp
alternative_if ARM64_SVE
	bl	__arm_smccc_sve_check
alternative_else_nop_endif
	\instr	#0
	ldr	x4, [sp, #16]
	ldr	x4, [sp]
	stp	x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
	stp	x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
	ldr	x4, [sp, #24]
	ldr	x4, [sp, #8]
	cbz	x4, 1f /* no quirk structure */
	ldr	x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
	cmp	x9, #ARM_SMCCC_QUIRK_QCOM_A6
	b.ne	1f
	str	x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
1:	ldp     x29, x30, [sp], #16
	ret
1:	ret
	.endm

/*
+0 −4
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;

bool __ro_after_init smccc_trng_available = false;
u64 __ro_after_init smccc_has_sve_hint = false;
s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED;
s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;

@@ -28,9 +27,6 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
	smccc_conduit = conduit;

	smccc_trng_available = smccc_probe_trng();
	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
	    smccc_version >= ARM_SMCCC_VERSION_1_3)
		smccc_has_sve_hint = true;

	if ((smccc_version >= ARM_SMCCC_VERSION_1_2) &&
	    (smccc_conduit != SMCCC_CONDUIT_NONE)) {
+3 −29
Original line number Diff line number Diff line
@@ -315,8 +315,6 @@ u32 arm_smccc_get_version(void);

void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit);

extern u64 smccc_has_sve_hint;

/**
 * arm_smccc_get_soc_id_version()
 *
@@ -414,15 +412,6 @@ struct arm_smccc_quirk {
	} state;
};

/**
 * __arm_smccc_sve_check() - Set the SVE hint bit when doing SMC calls
 *
 * Sets the SMCCC hint bit to indicate if there is live state in the SVE
 * registers, this modifies x0 in place and should never be called from C
 * code.
 */
asmlinkage unsigned long __arm_smccc_sve_check(unsigned long x0);

/**
 * __arm_smccc_smc() - make SMC calls
 * @a0-a7: arguments passed in registers 0 to 7
@@ -490,20 +479,6 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,

#endif

/* nVHE hypervisor doesn't have a current thread so needs separate checks */
#if defined(CONFIG_ARM64_SVE) && !defined(__KVM_NVHE_HYPERVISOR__)

#define SMCCC_SVE_CHECK ALTERNATIVE("nop \n",  "bl __arm_smccc_sve_check \n", \
				    ARM64_SVE)
#define smccc_sve_clobbers "x16", "x30", "cc",

#else

#define SMCCC_SVE_CHECK
#define smccc_sve_clobbers

#endif

#define __constraint_read_2	"r" (arg0)
#define __constraint_read_3	__constraint_read_2, "r" (arg1)
#define __constraint_read_4	__constraint_read_3, "r" (arg2)
@@ -574,12 +549,11 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
		register unsigned long r3 asm("r3"); 			\
		CONCATENATE(__declare_arg_,				\
			    COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__);	\
		asm volatile(SMCCC_SVE_CHECK				\
			     inst "\n" :				\
		asm volatile(inst "\n" :				\
			     "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)	\
			     : CONCATENATE(__constraint_read_,		\
					   COUNT_ARGS(__VA_ARGS__))	\
			     : smccc_sve_clobbers "memory");		\
			     : "memory");				\
		if (___res)						\
			*___res = (typeof(*___res)){r0, r1, r2, r3};	\
	} while (0)
@@ -628,7 +602,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
		asm ("" :						\
		     : CONCATENATE(__constraint_read_,			\
				   COUNT_ARGS(__VA_ARGS__))		\
		     : smccc_sve_clobbers "memory");			\
		     : "memory");					\
		if (___res)						\
			___res->a0 = SMCCC_RET_NOT_SUPPORTED;		\
	} while (0)