Skip to content

Commit f406055

Browse files
committed
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
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
2 parents fe69107 + ea0d55a commit f406055

File tree

2 files changed

+15
-4
lines changed

2 files changed

+15
-4
lines changed

arch/arm64/include/asm/sysreg.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,10 +1220,19 @@
12201220
__val; \
12211221
})
12221222

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

12291238
/*

arch/arm64/kernel/entry-common.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,8 @@ static void noinstr el0_breakpt(struct pt_regs *regs, unsigned long esr)
697697

698698
static void noinstr el0_softstp(struct pt_regs *regs, unsigned long esr)
699699
{
700+
bool step_done;
701+
700702
if (!is_ttbr0_addr(regs->pc))
701703
arm64_apply_bp_hardening();
702704

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

0 commit comments

Comments
 (0)