Commit f406055c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull arm64 fixes from Catalin Marinas:

 - Explicitly encode the XZR register if the value passed to
   write_sysreg_s() is 0.

   The GIC CDEOI instruction is encoded as a system register write with
   XZR as the source register. However, clang does not honour the "Z"
   register constraint, leading to incorrect code generation

 - Ensure the interrupts (DAIF.IF) are unmasked when completing
   single-step of a suspended breakpoint before calling
   exit_to_user_mode().

   With pseudo-NMIs, interrupts are (additionally) masked at the PMR_EL1
   register, handled by local_irq_*()

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: debug: always unmask interrupts in el0_softstp()
  arm64/sysreg: Fix GIC CDEOI instruction encoding
parents fe69107e ea0d55ae
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1220,10 +1220,19 @@
	__val;								\
})

/*
 * The "Z" constraint combined with the "%x0" template should be enough
 * to force XZR generation if (v) is a constant 0 value but LLVM does not
 * yet understand that modifier/constraint combo so a conditional is required
 * to nudge the compiler into using XZR as a source for a 0 constant value.
 */
#define write_sysreg_s(v, r) do {					\
	u64 __val = (u64)(v);						\
	u32 __maybe_unused __check_r = (u32)(r);			\
	asm volatile(__msr_s(r, "%x0") : : "rZ" (__val));		\
	if (__builtin_constant_p(__val) && __val == 0)			\
		asm volatile(__msr_s(r, "xzr"));			\
	else								\
		asm volatile(__msr_s(r, "%x0") : : "r" (__val));	\
} while (0)

/*
+5 −3
Original line number Diff line number Diff line
@@ -697,6 +697,8 @@ static void noinstr el0_breakpt(struct pt_regs *regs, unsigned long esr)

static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr)
{
	bool step_done;

	if (!is_ttbr0_addr(regs->pc))
		arm64_apply_bp_hardening();

@@ -707,10 +709,10 @@ static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr)
	 * If we are stepping a suspended breakpoint there's nothing more to do:
	 * the single-step is complete.
	 */
	if (!try_step_suspended_breakpoints(regs)) {
	step_done = try_step_suspended_breakpoints(regs);
	local_daif_restore(DAIF_PROCCTX);
	if (!step_done)
		do_el0_softstep(esr, regs);
	}
	arm64_exit_to_user_mode(regs);
}