Commit c97481ab authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'sched-urgent-2026-05-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull scheduler fix from Ingo Molnar:

 - Fix ARM64-specific rseq regressions (Mark Rutland)

* tag 'sched-urgent-2026-05-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  arm64/entry: Fix arm64-specific rseq brokenness
parents daa3de23 411c1cf4
Loading
Loading
Loading
Loading
+24 −7
Original line number Diff line number Diff line
@@ -62,6 +62,13 @@ static void noinstr arm64_exit_to_kernel_mode(struct pt_regs *regs,
	irqentry_exit_to_kernel_mode_after_preempt(regs, state);
}

static __always_inline void arm64_syscall_enter_from_user_mode(struct pt_regs *regs)
{
	enter_from_user_mode(regs);
	mte_disable_tco_entry(current);
	sme_enter_from_user_mode();
}

/*
 * Handle IRQ/context state management when entering from user mode.
 * Before this function is called it is not safe to call regular kernel code,
@@ -70,20 +77,30 @@ static void noinstr arm64_exit_to_kernel_mode(struct pt_regs *regs,
static __always_inline void arm64_enter_from_user_mode(struct pt_regs *regs)
{
	enter_from_user_mode(regs);
	rseq_note_user_irq_entry();
	mte_disable_tco_entry(current);
	sme_enter_from_user_mode();
}

static __always_inline void arm64_syscall_exit_to_user_mode(struct pt_regs *regs)
{
	local_irq_disable();
	syscall_exit_to_user_mode_prepare(regs);
	local_daif_mask();
	sme_exit_to_user_mode();
	mte_check_tfsr_exit();
	exit_to_user_mode();
}

/*
 * Handle IRQ/context state management when exiting to user mode.
 * After this function returns it is not safe to call regular kernel code,
 * instrumentable code, or any code which may trigger an exception.
 */

static __always_inline void arm64_exit_to_user_mode(struct pt_regs *regs)
{
	local_irq_disable();
	exit_to_user_mode_prepare_legacy(regs);
	irqentry_exit_to_user_mode_prepare(regs);
	local_daif_mask();
	sme_exit_to_user_mode();
	mte_check_tfsr_exit();
@@ -92,7 +109,7 @@ static __always_inline void arm64_exit_to_user_mode(struct pt_regs *regs)

asmlinkage void noinstr asm_exit_to_user_mode(struct pt_regs *regs)
{
	arm64_exit_to_user_mode(regs);
	arm64_syscall_exit_to_user_mode(regs);
}

/*
@@ -716,12 +733,12 @@ static void noinstr el0_brk64(struct pt_regs *regs, unsigned long esr)

static void noinstr el0_svc(struct pt_regs *regs)
{
	arm64_enter_from_user_mode(regs);
	arm64_syscall_enter_from_user_mode(regs);
	cortex_a76_erratum_1463225_svc_handler();
	fpsimd_syscall_enter();
	local_daif_restore(DAIF_PROCCTX);
	do_el0_svc(regs);
	arm64_exit_to_user_mode(regs);
	arm64_syscall_exit_to_user_mode(regs);
	fpsimd_syscall_exit();
}

@@ -868,11 +885,11 @@ static void noinstr el0_cp15(struct pt_regs *regs, unsigned long esr)

static void noinstr el0_svc_compat(struct pt_regs *regs)
{
	arm64_enter_from_user_mode(regs);
	arm64_syscall_enter_from_user_mode(regs);
	cortex_a76_erratum_1463225_svc_handler();
	local_daif_restore(DAIF_PROCCTX);
	do_el0_svc_compat(regs);
	arm64_exit_to_user_mode(regs);
	arm64_syscall_exit_to_user_mode(regs);
}

static void noinstr el0_bkpt32(struct pt_regs *regs, unsigned long esr)
+0 −8
Original line number Diff line number Diff line
@@ -218,14 +218,6 @@ static __always_inline void __exit_to_user_mode_validate(void)
	lockdep_sys_exit();
}

/* Temporary workaround to keep ARM64 alive */
static __always_inline void exit_to_user_mode_prepare_legacy(struct pt_regs *regs)
{
	__exit_to_user_mode_prepare(regs, EXIT_TO_USER_MODE_WORK);
	rseq_exit_to_user_mode_legacy();
	__exit_to_user_mode_validate();
}

/**
 * syscall_exit_to_user_mode_prepare - call exit_to_user_mode_loop() if required
 * @regs:	Pointer to pt_regs on entry stack
+0 −19
Original line number Diff line number Diff line
@@ -749,24 +749,6 @@ static __always_inline void rseq_irqentry_exit_to_user_mode(void)
	ev->events = 0;
}

/* Required to keep ARM64 working */
static __always_inline void rseq_exit_to_user_mode_legacy(void)
{
	struct rseq_event *ev = &current->rseq.event;

	rseq_stat_inc(rseq_stats.exit);

	if (static_branch_unlikely(&rseq_debug_enabled))
		WARN_ON_ONCE(ev->sched_switch);

	/*
	 * Ensure that event (especially user_irq) is cleared when the
	 * interrupt did not result in a schedule and therefore the
	 * rseq processing did not clear it.
	 */
	ev->events = 0;
}

void __rseq_debug_syscall_return(struct pt_regs *regs);

static __always_inline void rseq_debug_syscall_return(struct pt_regs *regs)
@@ -782,7 +764,6 @@ static inline bool rseq_exit_to_user_mode_restart(struct pt_regs *regs, unsigned
}
static inline void rseq_syscall_exit_to_user_mode(void) { }
static inline void rseq_irqentry_exit_to_user_mode(void) { }
static inline void rseq_exit_to_user_mode_legacy(void) { }
static inline void rseq_debug_syscall_return(struct pt_regs *regs) { }
static inline bool rseq_grant_slice_extension(unsigned long ti_work, unsigned long mask) { return false; }
#endif /* !CONFIG_RSEQ */