mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v20 00/15] arm64: entry: Convert to Generic Entry
@ 2026-09-30 10:17 Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 01/15] arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP Jinjie Ruan
                   ` (15 more replies)
  0 siblings, 16 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

This series converts arm64 to the generic entry infrastructure.

Currently, architectures such as x86, RISC-V, LoongArch, PowerPC
and s390 use generic entry, which significantly reduces maintenance
burden and improves code elegance.  arm64 already adopted generic IRQ
entry in commit b3cf07851b6c ("arm64: entry: Switch to generic IRQ entry"),
making it the right time to complete the conversion.

This work brings arm64 in line with other major architectures,
reducing duplicated code and enabling future improvements like
Syscall User Dispatch and rseq time slice extension optimizations.

The series is rebased on v7.3-rc4 and has been tested with stress-ng,
hackbench, kselftests (ptrace, breakpoints, arm64/abi, arm64/fp, vDSO),
ptrace stress test, Pseudo-NMI load test, and the rr test suite [1].

A new kselftest ("selftests/arm64: Add ptrace SYSEMU/single-step tests")
is included at the end of the series, covering the syscall-exit
pseudo-step and single-step behaviour touched by this work.

Observable (non-ABI) changes worth calling out:

- The traceable functions on the syscall path change: syscall_trace_enter,
  syscall_trace_exit and el0_svc_common.constprop.0 are replaced by
  trace_syscall_enter, trace_syscall_exit and syscall_enter_audit, the
  same names x86, RISC-V, LoongArch and s390 already expose.

- CONFIG_DEBUG_RSEQ becomes unselectable on arm64 once GENERIC_ENTRY is
  set (rseq_syscall() becomes a no-op stub), so the earlier rseq_syscall()
  reordering is only temporary and the equivalent is handled by
  __rseq_debug_syscall_return().

On gVisor with systrap mode, the Syscall User Dispatch (SUD) feature
yields a slightly lower performance gain on arm64 (3% ~ 5%), similar to
that on x86 [2].

Result: the average over 1M getpid calls, ns/op

	| KVM VM Configuration | SUD    | no-SUD | Savings % |
	| -------------------  | -----  | -------| --------- |
	| 2 vCPU, pinned       | 4269.8 | 4509.5 | 5.3%      |
	| 4 vCPU, pinned       | 4175.4 | 4369.1 | 4.4%      |
	| 8 vCPU, pinned       | 4352.6 | 4485.4 | 3.0%      |

Note that this series does not yet enable SUD or the rseq time slice
extension on arm64: SUD additionally needs
ARCH_SUPPORTS_SYSCALL_USER_DISPATCH [3] and the rseq slice extension needs
HAVE_GENERIC_TIF_BITS [4], neither of which arm64 selects today.  The
numbers above are the motivation for enabling them in a follow-up.

Testing follow-up that still requires real hardware:

- MTE: run the MTE selftests on real hardware; part of them do not run
  under QEMU.

[1]: https://github.com/rr-debugger/rr/wiki/Building-And-Installing#tests
[2]: https://github.com/google/gvisor/commit/a45d6227b521012109cde9a942d644d778eb773b
[3]: https://lore.kernel.org/all/20260721081858.1169276-16-ruanjinjie@huawei.com/
[4]: https://lore.kernel.org/all/20260320104222.1381274-1-ruanjinjie@huawei.com/

Changes in v20:
- Add a kselftest covering the syscall-exit pseudo-step
  and single-step behaviour.
- Reword the first patch: it skips the pseudo-step for the emulated
  syscall rather than "fixing a redundant exit stop", and drop the
  Fixes: tag and Reviewed-by.
- Add Tested-by.
- Cover letter: document the observable changes and the testing
  follow-ups.
- Link to v19: https://lore.kernel.org/all/20260922035510.1090299-1-ruanjinjie@huawei.com/

Changes in v19:
- Rebased on v7.3-rc4.
- Fix build problem as Karl pointed out.
- Remove has_syscall_work() later to make it more clear.
- Add gvisor test data.
- Link to v18: https://lore.kernel.org/all/20260902095537.602517-2-ruanjinjie@huawei.com/

Changes in v18:
- Rebased on v7.3-rc1.
- Drop the SUD patch as Mark suggeted.
- Update the commit message.
- Add Reviewed-by.
- Link to v17: https://lore.kernel.org/all/20260721081858.1169276-1-ruanjinjie@huawei.com/

For changes in v7 to v16, please refer to the individual patch threads:
- v16: https://lore.kernel.org/all/20260629130616.642022-1-ruanjinjie@huawei.com/
- v15: https://lore.kernel.org/all/20260511092103.1974980-1-ruanjinjie@huawei.com/
- v14: https://lore.kernel.org/all/20260320102620.1336796-1-ruanjinjie@huawei.com/
- v13: https://lore.kernel.org/all/20260317082020.737779-1-ruanjinjie@huawei.com/
- v12: https://lore.kernel.org/all/20260203133728.848283-1-ruanjinjie@huawei.com/
- v11: https://lore.kernel.org/all/20260128031934.3906955-1-ruanjinjie@huawei.com/
- v10: https://lore.kernel.org/all/20251222114737.1334364-1-ruanjinjie@huawei.com/
- v9: https://lore.kernel.org/all/20251204082123.2792067-1-ruanjinjie@huawei.com/
- v8: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie@huawei.com/
- v7: https://lore.kernel.org/all/20251117133048.53182-1-ruanjinjie@huawei.com/



Jinjie Ruan (15):
  arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP
  arm64: ptrace: Rework audit_syscall_entry()
  arm64: ptrace: Open-code seccomp check in syscall_trace_enter()
  arm64: ptrace: Rename and clean up syscall_trace_enter()
  arm64: ptrace: Protect rseq_syscall() from tracer PC modifications
  arm64: syscall: Rework the syscall exit path in el0_svc_common()
  arm64: ptrace: Pass thread flags to trace enter/exit
  arm64: ptrace: Extract arm64_syscall_exit_to_user_mode_work() helper
  arm64: ptrace: Align syscall exit work semantics with generic entry
  arm64: syscall: Use exit-specific flags check in el0_svc_common()
  arm64: syscall: Simplify el0_svc_common() syscall exit path
  arm64: ptrace: Make return type of arm64_syscall_trace_enter() bool
  arm64: entry: Convert to generic entry
  arm64: Inline el0_svc_common()
  selftests/arm64: Add ptrace SYSEMU/single-step tests

 arch/arm64/Kconfig                            |   2 +-
 arch/arm64/include/asm/entry-common.h         |  77 ++++++++++
 arch/arm64/include/asm/syscall.h              |   5 +-
 arch/arm64/include/asm/thread_info.h          |  16 +--
 arch/arm64/kernel/debug-monitors.c            |   8 ++
 arch/arm64/kernel/entry-common.c              |   2 +-
 arch/arm64/kernel/ptrace.c                    | 115 ---------------
 arch/arm64/kernel/signal.c                    |   2 +-
 arch/arm64/kernel/syscall.c                   |  34 ++---
 tools/testing/selftests/arm64/Makefile        |   2 +-
 tools/testing/selftests/arm64/ptrace/Makefile |   9 ++
 .../selftests/arm64/ptrace/ptrace_common.h    |  84 +++++++++++
 .../arm64/ptrace/single_step_signal_handler.c | 131 ++++++++++++++++++
 .../arm64/ptrace/single_step_syscall_stop.c   | 130 +++++++++++++++++
 .../ptrace/sysemu_singlestep_intercept.c      |  93 +++++++++++++
 .../ptrace/sysemu_singlestep_no_exit_stop.c   |  81 +++++++++++
 16 files changed, 631 insertions(+), 160 deletions(-)
 create mode 100644 tools/testing/selftests/arm64/ptrace/Makefile
 create mode 100644 tools/testing/selftests/arm64/ptrace/ptrace_common.h
 create mode 100644 tools/testing/selftests/arm64/ptrace/single_step_signal_handler.c
 create mode 100644 tools/testing/selftests/arm64/ptrace/single_step_syscall_stop.c
 create mode 100644 tools/testing/selftests/arm64/ptrace/sysemu_singlestep_intercept.c
 create mode 100644 tools/testing/selftests/arm64/ptrace/sysemu_singlestep_no_exit_stop.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 01/15] arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 02/15] arm64: ptrace: Rework audit_syscall_entry() Jinjie Ruan
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

PTRACE_SYSEMU_SINGLESTEP sets both _TIF_SYSCALL_EMU and _TIF_SINGLESTEP.

With _TIF_SINGLESTEP set, the arm64 syscall-exit path synthesises a
pseudo-single-step exception:

	ptrace_report_syscall_exit(regs, 1)
	  -> user_single_step_report()
	     -> info.si_signo = SIGTRAP
	     -> info.si_code = SI_USER
	     -> force_sig_info(&info)

But for PTRACE_SYSEMU_SINGLESTEP it is redundant: the stop before
the instruction following the SVC is already delivered by the hardware
single-step state machine, so the tracer ends up with two stops
at the same PC as below:

	sig=133 si_code=133  SS=0  pc=0x400638   [syscall-enter-stop]
	sig=5   si_code=0    SS=0  pc=0x400638   [pseudo-step, dropped here]
	sig=5   si_code=2    SS=1  pc=0x400638   [hardware single-step]

The pseudo-step was added by commit ac2081cdc4d9 ("arm64: ptrace:
Consistently use pseudo-singlestep exceptions") because a ptrace stop
taken while a system call is in progress may corrupt the stepping state.
For an emulated system call that cannot happen, as the call never runs:

- No syscall-exit-stop, because _TIF_SINGLESTEP is set

- No seccomp trap, because syscall_trace_enter() returns NO_SYSCALL
  when SYSCALL_EMU is set, before the seccomp check

- The syscall body is not executed, so nothing can take a stop while it
  is in progress.

Introduce report_single_step(), which returns false when _TIF_SYSCALL_EMU
is set, so the pseudo-step is skipped for the emulated case. This also
matches the generic entry behaviour.

PTRACE_SINGLESTEP and PTRACE_SYSCALL are unaffected:
- PTRACE_SYSCALL: SYSCALL_TRACE is set and _TIF_SINGLESTEP is not, so
  the syscall-exit-stop is reported as before and no pseudo-step is
  involved;

- PTRACE_SINGLESTEP: _TIF_SINGLESTEP is set but _TIF_SYSCALL_EMU is
  not, so the pseudo-step is still synthesised.  It is still needed
  here, because the system call does execute and the hazard described
  above applies.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/ptrace.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index f743cbec1c3a..96462de75d4b 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2482,16 +2482,26 @@ int syscall_trace_enter(struct pt_regs *regs)
 	return regs->syscallno;
 }
 
+static inline bool report_single_step(unsigned long flags)
+{
+	if (flags & _TIF_SYSCALL_EMU)
+		return false;
+
+	return flags & _TIF_SINGLESTEP;
+}
+
 void syscall_trace_exit(struct pt_regs *regs)
 {
 	unsigned long flags = read_thread_flags();
+	bool step;
 
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
 		trace_sys_exit(regs, syscall_get_return_value(current, regs));
 
-	if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))
+	step = report_single_step(flags);
+	if (step || flags & _TIF_SYSCALL_TRACE)
 		report_syscall_exit(regs);
 
 	rseq_syscall(regs);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 02/15] arm64: ptrace: Rework audit_syscall_entry()
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 01/15] arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 03/15] arm64: ptrace: Open-code seccomp check in syscall_trace_enter() Jinjie Ruan
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Extract syscall_enter_audit() helper and switch to generic helpers to
get syscall number and syscall arguments, matching the generic entry
implementation.

The new code:
- Checks audit_context() first to avoid unnecessary work when audit
  is not active.
- Use syscall_get_arguments() helper instead of directly accessing
  regs fields.
- Use syscall_get_nr() helper to get syscall number instead of directly
  accessing regs->syscallno.
- Now exactly equivalent to generic entry's syscall_enter_audit().

This is a preparation step for converting arm64 to the generic entry
infrastructure. No functional changes intended.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/ptrace.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 96462de75d4b..573b5770698f 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2458,6 +2458,19 @@ static void report_syscall_exit(struct pt_regs *regs)
 	}
 }
 
+#ifdef CONFIG_AUDITSYSCALL
+static inline void syscall_enter_audit(struct pt_regs *regs)
+{
+	long syscall = syscall_get_nr(current, regs);
+	unsigned long args[6];
+
+	syscall_get_arguments(current, regs, args);
+	__audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
+}
+#else
+static inline void syscall_enter_audit(struct pt_regs *regs) { }
+#endif
+
 int syscall_trace_enter(struct pt_regs *regs)
 {
 	unsigned long flags = read_thread_flags();
@@ -2476,8 +2489,8 @@ int syscall_trace_enter(struct pt_regs *regs)
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 		trace_sys_enter(regs, regs->syscallno);
 
-	audit_syscall_entry(regs->syscallno, regs->orig_x0, regs->regs[1],
-			    regs->regs[2], regs->regs[3]);
+	if (unlikely(audit_context()))
+		syscall_enter_audit(regs);
 
 	return regs->syscallno;
 }
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 03/15] arm64: ptrace: Open-code seccomp check in syscall_trace_enter()
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 01/15] arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 02/15] arm64: ptrace: Rework audit_syscall_entry() Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 04/15] arm64: ptrace: Rename and clean up syscall_trace_enter() Jinjie Ruan
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Refactor syscall_trace_enter() by open-coding the seccomp check to
align with the generic entry framework.

The generic entry implementation expands the seccomp check in-place
by testing SYSCALL_WORK_SECCOMP and directly calling the underlying
__seccomp_permit_syscall() function. Moreover, generic entry explicitly
re-reads work flags after ptrace handling to ensure any updates to
seccomp work flags during the ptrace stop are observed.

Bring arm64 in line with this behavior:
- Re-read thread flags after ptrace handling.

- Test the updated flags for _TIF_SECCOMP and call
  __seccomp_permit_syscall().

No functional changes are intended; this change simplifies future
migration to the generic entry framework.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/all/20260713025712.416366-1-ruanjinjie@huawei.com/
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/ptrace.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 573b5770698f..f68de40fd351 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2480,11 +2480,16 @@ int syscall_trace_enter(struct pt_regs *regs)
 		ret = report_syscall_entry(regs);
 		if (ret || (flags & _TIF_SYSCALL_EMU))
 			return NO_SYSCALL;
+
+		/* ptrace might have changed thread flags */
+		flags = read_thread_flags();
 	}
 
 	/* Do the secure computing after ptrace; failures should be fast. */
-	if (!seccomp_permit_syscall())
-		return NO_SYSCALL;
+	if (unlikely(flags & _TIF_SECCOMP)) {
+		if (!__seccomp_permit_syscall())
+			return NO_SYSCALL;
+	}
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 		trace_sys_enter(regs, regs->syscallno);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 04/15] arm64: ptrace: Rename and clean up syscall_trace_enter()
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (2 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 03/15] arm64: ptrace: Open-code seccomp check in syscall_trace_enter() Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 05/15] arm64: ptrace: Protect rseq_syscall() from tracer PC modifications Jinjie Ruan
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Rename syscall_trace_enter() to arm64_syscall_trace_enter() to avoid
name collisions and clarify the boundary when arm64 eventually switches
to the generic entry infrastructure.

In addition, replace direct accesses to regs->syscallno with the standard
syscall_get_nr() helper for both trace_sys_enter() and the return value.
This decouples the tracing logic from architecture-specific struct pt_regs
layouts, aligning the implementation with the generic entry pattern.

No functional changes intended; this is a preparation step for
converting arm64 to the generic entry infrastructure.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/include/asm/syscall.h | 2 +-
 arch/arm64/kernel/ptrace.c       | 6 +++---
 arch/arm64/kernel/syscall.c      | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 5e4c7fc44f73..d1dabdcde41c 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,7 +120,7 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int syscall_trace_enter(struct pt_regs *regs);
+int arm64_syscall_trace_enter(struct pt_regs *regs);
 void syscall_trace_exit(struct pt_regs *regs);
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index f68de40fd351..96c03922baa5 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2471,7 +2471,7 @@ static inline void syscall_enter_audit(struct pt_regs *regs)
 static inline void syscall_enter_audit(struct pt_regs *regs) { }
 #endif
 
-int syscall_trace_enter(struct pt_regs *regs)
+int arm64_syscall_trace_enter(struct pt_regs *regs)
 {
 	unsigned long flags = read_thread_flags();
 	int ret;
@@ -2492,12 +2492,12 @@ int syscall_trace_enter(struct pt_regs *regs)
 	}
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
-		trace_sys_enter(regs, regs->syscallno);
+		trace_sys_enter(regs, syscall_get_nr(current, regs));
 
 	if (unlikely(audit_context()))
 		syscall_enter_audit(regs);
 
-	return regs->syscallno;
+	return syscall_get_nr(current, regs);
 }
 
 static inline bool report_single_step(unsigned long flags)
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 358ddfbf1401..3e78e159b2a1 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -113,7 +113,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = syscall_trace_enter(regs);
+		scno = arm64_syscall_trace_enter(regs);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 05/15] arm64: ptrace: Protect rseq_syscall() from tracer PC modifications
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (3 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 04/15] arm64: ptrace: Rename and clean up syscall_trace_enter() Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 06/15] arm64: syscall: Rework the syscall exit path in el0_svc_common() Jinjie Ruan
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Move the rseq_syscall() check earlier in the syscall exit path to ensure
it operates on the original instruction pointer (regs->pc) before any
potential modification by a tracer.

[Background]
When CONFIG_DEBUG_RSEQ is enabled, rseq_syscall() verifies that a system
call was not executed within an rseq critical section by examining
regs->pc. If a violation is detected, it triggers a SIGSEGV.

[Problem]
Currently, arm64 invokes rseq_syscall() after report_syscall_exit().
However, during report_syscall_exit(), a ptrace tracer can modify the
task's instruction pointer via PTRACE_SETREGSET (with NT_PRSTATUS). This
leads to an inconsistency where rseq may analyze a post-trace PC instead
of the actual PC at the time of syscall exit.

[Why this matters]
The rseq check is intended to validate the execution context of the
syscall itself. Analyzing a tracer-modified PC can lead to incorrect
detection or missed violations. Moving the check earlier ensures rseq
sees the authentic state of the task.

[Alignment]
This change aligns arm64 with:
- Generic entry, which calls rseq_syscall() first.
- arm32 implementation, which also performs the check before audit.

[Impact]
There is no functional change to signal delivery; SIGSEGV will still be
processed in arm64_exit_to_user_mode() at the end of the exit path.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Thomas Gleixner <tglx@kernel.org>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/ptrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 96c03922baa5..72df4b84ec9a 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2513,6 +2513,8 @@ void syscall_trace_exit(struct pt_regs *regs)
 	unsigned long flags = read_thread_flags();
 	bool step;
 
+	rseq_syscall(regs);
+
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
@@ -2521,8 +2523,6 @@ void syscall_trace_exit(struct pt_regs *regs)
 	step = report_single_step(flags);
 	if (step || flags & _TIF_SYSCALL_TRACE)
 		report_syscall_exit(regs);
-
-	rseq_syscall(regs);
 }
 
 /*
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 06/15] arm64: syscall: Rework the syscall exit path in el0_svc_common()
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (4 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 05/15] arm64: ptrace: Protect rseq_syscall() from tracer PC modifications Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 07/15] arm64: ptrace: Pass thread flags to trace enter/exit Jinjie Ruan
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

In preparation for moving arm64 over to the generic entry,
invert the nested conditional flags check within el0_svc_common().

No functional changes.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/syscall.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 3e78e159b2a1..b8d7d29a431b 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -127,8 +127,9 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	 */
 	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
 		flags = read_thread_flags();
-		if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP))
-			return;
+		if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+			syscall_trace_exit(regs);
+		return;
 	}
 
 trace_exit:
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 07/15] arm64: ptrace: Pass thread flags to trace enter/exit
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (5 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 06/15] arm64: syscall: Rework the syscall exit path in el0_svc_common() Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 08/15] arm64: ptrace: Extract arm64_syscall_exit_to_user_mode_work() helper Jinjie Ruan
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Move the reading of thread flags from inside arm64_syscall_trace_enter()
and syscall_trace_exit() to their callers.  This aligns the function
signatures with the generic entry framework, where the caller
is responsible for supplying the flags.

In el0_svc_common(), the flags are now passed directly to the tracing
functions, and re-read before the enter/exit path to reflect any updates.

No functional change intended; this is a preparatory step for
converting arm64 to the generic entry infrastructure.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/include/asm/syscall.h |  4 ++--
 arch/arm64/kernel/ptrace.c       |  6 ++----
 arch/arm64/kernel/syscall.c      | 11 +++++++----
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index d1dabdcde41c..696739f5a250 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,7 +120,7 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int arm64_syscall_trace_enter(struct pt_regs *regs);
-void syscall_trace_exit(struct pt_regs *regs);
+int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
+void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 72df4b84ec9a..ac90b05dbd11 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2471,9 +2471,8 @@ static inline void syscall_enter_audit(struct pt_regs *regs)
 static inline void syscall_enter_audit(struct pt_regs *regs) { }
 #endif
 
-int arm64_syscall_trace_enter(struct pt_regs *regs)
+int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags)
 {
-	unsigned long flags = read_thread_flags();
 	int ret;
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
@@ -2508,9 +2507,8 @@ static inline bool report_single_step(unsigned long flags)
 	return flags & _TIF_SINGLESTEP;
 }
 
-void syscall_trace_exit(struct pt_regs *regs)
+void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
 {
-	unsigned long flags = read_thread_flags();
 	bool step;
 
 	rseq_syscall(regs);
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index b8d7d29a431b..e778aac6fab9 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -113,7 +113,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = arm64_syscall_trace_enter(regs);
+		scno = arm64_syscall_trace_enter(regs, read_thread_flags());
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
@@ -127,13 +127,16 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	 */
 	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
 		flags = read_thread_flags();
-		if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
-			syscall_trace_exit(regs);
+		if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP) {
+			flags = read_thread_flags();
+			syscall_trace_exit(regs, flags);
+		}
 		return;
 	}
 
 trace_exit:
-	syscall_trace_exit(regs);
+	flags = read_thread_flags();
+	syscall_trace_exit(regs, flags);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 08/15] arm64: ptrace: Extract arm64_syscall_exit_to_user_mode_work() helper
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (6 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 07/15] arm64: ptrace: Pass thread flags to trace enter/exit Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:17 ` [PATCH v20 09/15] arm64: ptrace: Align syscall exit work semantics with generic entry Jinjie Ruan
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Introduce a helper arm64_syscall_exit_to_user_mode_work() that
encapsulates the re-reading of thread flags and the call to
syscall_trace_exit(). Use it in el0_svc_common() to replace
the open-coded instances, removing the duplicated flags read
and making the control flow simpler.

This aligns the arm64 exit path with the pattern expected by the
generic entry infrastructure, which uses a similar
syscall_exit_to_user_mode_work() callback.

No functional changes intended; this is a preparation step for converting
arm64 to the generic entry infrastructure.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/include/asm/syscall.h | 7 +++++++
 arch/arm64/kernel/syscall.c      | 9 +++------
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 696739f5a250..3e4672ab4a4f 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -123,4 +123,11 @@ static inline int syscall_get_arch(struct task_struct *task)
 int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
 void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
 
+static __always_inline void arm64_syscall_exit_to_user_mode_work(struct pt_regs *regs)
+{
+	unsigned long flags = read_thread_flags();
+
+	syscall_trace_exit(regs, flags);
+}
+
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index e778aac6fab9..0061fc63e7ba 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -127,16 +127,13 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	 */
 	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
 		flags = read_thread_flags();
-		if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP) {
-			flags = read_thread_flags();
-			syscall_trace_exit(regs, flags);
-		}
+		if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+			arm64_syscall_exit_to_user_mode_work(regs);
 		return;
 	}
 
 trace_exit:
-	flags = read_thread_flags();
-	syscall_trace_exit(regs, flags);
+	arm64_syscall_exit_to_user_mode_work(regs);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 09/15] arm64: ptrace: Align syscall exit work semantics with generic entry
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (7 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 08/15] arm64: ptrace: Extract arm64_syscall_exit_to_user_mode_work() helper Jinjie Ruan
@ 2026-09-30 10:17 ` Jinjie Ruan
  2026-09-30 10:18 ` [PATCH v20 10/15] arm64: syscall: Use exit-specific flags check in el0_svc_common() Jinjie Ruan
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:17 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Refactor the syscall exit path to better match the generic entry
framework. Specifically:

- Introduce `_TIF_SYSCALL_EXIT_WORK` to aggregate exit-time thread
  flags (trace, audit, tracepoint).

- Rename `syscall_trace_exit()` to `arm64_syscall_exit_work()` to
  better reflect its role.

- Move `rseq_syscall()` out of `arm64_syscall_exit_work()` and into
  `arm64_syscall_exit_to_user_mode_work()` so that it runs
  unconditionally on all exits, consistent with generic entry.

- Gate `arm64_syscall_exit_work()` behind the new flag check,
  mirroring the generic entry exit's pattern.

Gating audit on `_TIF_SYSCALL_AUDIT` is equivalent to the previous
`audit_context()` check: the audit context and flag are statically
allocated at fork and freed at exit, remaining stable throughout
syscall execution.

No functional changes intended.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/include/asm/syscall.h     | 8 ++++++--
 arch/arm64/include/asm/thread_info.h | 3 +++
 arch/arm64/kernel/ptrace.c           | 5 +----
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 3e4672ab4a4f..7cc872fde019 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -8,6 +8,7 @@
 #include <uapi/linux/audit.h>
 #include <linux/compat.h>
 #include <linux/err.h>
+#include <linux/rseq.h>
 
 typedef long (*syscall_fn_t)(const struct pt_regs *regs);
 
@@ -121,13 +122,16 @@ static inline int syscall_get_arch(struct task_struct *task)
 }
 
 int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
+void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags);
 
 static __always_inline void arm64_syscall_exit_to_user_mode_work(struct pt_regs *regs)
 {
 	unsigned long flags = read_thread_flags();
 
-	syscall_trace_exit(regs, flags);
+	rseq_syscall(regs);
+
+	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
+		arm64_syscall_exit_work(regs, flags);
 }
 
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 5d7fe3e153c8..56a2c9426a32 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -112,6 +112,9 @@ void arch_setup_new_exec(void);
 				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
 				 _TIF_SYSCALL_EMU)
 
+#define _TIF_SYSCALL_EXIT_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+				 _TIF_SYSCALL_TRACEPOINT)
+
 #ifdef CONFIG_SHADOW_CALL_STACK
 #define INIT_SCS							\
 	.scs_base	= init_shadow_call_stack,			\
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index ac90b05dbd11..610a79c1072b 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -28,7 +28,6 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/regset.h>
 #include <linux/elf.h>
-#include <linux/rseq.h>
 
 #include <asm/compat.h>
 #include <asm/cpufeature.h>
@@ -2507,12 +2506,10 @@ static inline bool report_single_step(unsigned long flags)
 	return flags & _TIF_SINGLESTEP;
 }
 
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
+void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags)
 {
 	bool step;
 
-	rseq_syscall(regs);
-
 	audit_syscall_exit(regs);
 
 	if (flags & _TIF_SYSCALL_TRACEPOINT)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 10/15] arm64: syscall: Use exit-specific flags check in el0_svc_common()
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (8 preceding siblings ...)
  2026-09-30 10:17 ` [PATCH v20 09/15] arm64: ptrace: Align syscall exit work semantics with generic entry Jinjie Ruan
@ 2026-09-30 10:18 ` Jinjie Ruan
  2026-09-30 10:18 ` [PATCH v20 11/15] arm64: syscall: Simplify el0_svc_common() syscall exit path Jinjie Ruan
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:18 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

The syscall exit path in el0_svc_common() re-evaluates all
_TIF_SYSCALL_WORK flags, but this mask contains flags that only
matter on entry:

- _TIF_SECCOMP: seccomp filtering is entry-only
- _TIF_SYSCALL_EMU: PTRACE_SYSEMU skips the syscall on entry

Re-checking them on exit is unnecessary and may trigger redundant work.

Switch to _TIF_SYSCALL_EXIT_WORK for the exit-path re-check to evaluate
only exit-relevant flags (_TIF_SYSCALL_TRACE, _TIF_SYSCALL_AUDIT, and
_TIF_SYSCALL_TRACEPOINT).

No functional change intended.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/syscall.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 0061fc63e7ba..f1f0b6f3e32b 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -127,7 +127,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	 */
 	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
 		flags = read_thread_flags();
-		if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP)
+		if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
 			arm64_syscall_exit_to_user_mode_work(regs);
 		return;
 	}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 11/15] arm64: syscall: Simplify el0_svc_common() syscall exit path
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (9 preceding siblings ...)
  2026-09-30 10:18 ` [PATCH v20 10/15] arm64: syscall: Use exit-specific flags check in el0_svc_common() Jinjie Ruan
@ 2026-09-30 10:18 ` Jinjie Ruan
  2026-09-30 10:18 ` [PATCH v20 12/15] arm64: ptrace: Make return type of arm64_syscall_trace_enter() bool Jinjie Ruan
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:18 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Remove the redundant nested conditional check within the system call
exit path of el0_svc_common() to streamline the exit sequence.

The fast-path block is guarded by `!IS_ENABLED(CONFIG_DEBUG_RSEQ)`,
so CONFIG_DEBUG_RSEQ is guaranteed to be disabled and the call of
rseq_syscall() is a no-op. Under this constraint, the code logic
inside the block becomes completely identical to what
the arm64_syscall_exit_to_user_mode_work() helper already does.
Replace that nested logic with a direct invocation of the helper,
eliminating redundant code.

Before:

| if (... && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
| 	flags = read_thread_flags();
| 	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
| 		arm64_syscall_exit_to_user_mode_work(regs);
| 	return;
| }
| trace_exit:
|	arm64_syscall_exit_to_user_mode_work(regs);

After simplify:

| if (... && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
|	arm64_syscall_exit_to_user_mode_work(regs);
|	return;
| }
| trace_exit:
|	arm64_syscall_exit_to_user_mode_work(regs);

Furthermore, Since both the conditional fast-path and the fallback
slow-path now uniformly invoke arm64_syscall_exit_to_user_mode_work(),
this explicit conditional branch is entirely redundant regardless of
whether the evaluation is true or false. Removing it collapses
the duplicated logic into a single, unconditional path.

Also remove has_syscall_work(). No functional changes indeed.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/syscall.c | 20 +-------------------
 1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index f1f0b6f3e32b..3488afd45d20 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -54,11 +54,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	syscall_set_return_value(current, regs, 0, ret);
 }
 
-static inline bool has_syscall_work(unsigned long flags)
-{
-	return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
 static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 			   const syscall_fn_t syscall_table[])
 {
@@ -95,7 +90,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		return;
 	}
 
-	if (has_syscall_work(flags)) {
+	if (unlikely(flags & _TIF_SYSCALL_WORK)) {
 		/*
 		 * The de-facto standard way to skip a system call using ptrace
 		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
@@ -119,19 +114,6 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	}
 
 	invoke_syscall(regs, scno, sc_nr, syscall_table);
-
-	/*
-	 * The tracing status may have changed under our feet, so we have to
-	 * check again. However, if we were tracing entry, then we always trace
-	 * exit regardless, as the old entry assembly did.
-	 */
-	if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
-		flags = read_thread_flags();
-		if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
-			arm64_syscall_exit_to_user_mode_work(regs);
-		return;
-	}
-
 trace_exit:
 	arm64_syscall_exit_to_user_mode_work(regs);
 }
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 12/15] arm64: ptrace: Make return type of arm64_syscall_trace_enter() bool
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (10 preceding siblings ...)
  2026-09-30 10:18 ` [PATCH v20 11/15] arm64: syscall: Simplify el0_svc_common() syscall exit path Jinjie Ruan
@ 2026-09-30 10:18 ` Jinjie Ruan
  2026-09-30 10:18 ` [PATCH v20 13/15] arm64: entry: Convert to generic entry Jinjie Ruan
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:18 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

In preparation for migrating arm64 to the generic entry infrastructure,
decouple the decision to execute the syscall from the syscall number
itself. The ptrace and seccomp now returns a boolean flag rather than
overloading NO_SYSCALL (-1).

Changes:
- arm64_syscall_trace_enter() returns bool:
  - false: abort syscall execution
  - true: proceed, with syscall number reread from regs
- If we decide to execute the syscall, reread the syscall number
  and check if it is NO_SYSCALL again. Because when a tracer sets
  the syscall number to -1 and provides a custom return value in x0,
  this avoids calling invoke_syscall() which would overwrite the custom
  value with -ENOSYS by sys_ni_syscall().

Behavioral impact (unchanged):
- User-issued syscall(-1): unchanged, returns -ENOSYS.
- Tracer skip with custom x0: unchanged, returns custom x0
- Tracer skip without setting x0: unchanged, returns original
  argument (garbage)
- Normal syscalls and seccomp rejects: unaffected

No functional changes.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/include/asm/syscall.h | 2 +-
 arch/arm64/kernel/ptrace.c       | 8 ++++----
 arch/arm64/kernel/syscall.c      | 6 +++++-
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 7cc872fde019..f19d4a8824ba 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -121,7 +121,7 @@ static inline int syscall_get_arch(struct task_struct *task)
 	return AUDIT_ARCH_AARCH64;
 }
 
-int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
+bool arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
 void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags);
 
 static __always_inline void arm64_syscall_exit_to_user_mode_work(struct pt_regs *regs)
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 610a79c1072b..c304c062abbb 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -2470,14 +2470,14 @@ static inline void syscall_enter_audit(struct pt_regs *regs)
 static inline void syscall_enter_audit(struct pt_regs *regs) { }
 #endif
 
-int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags)
+bool arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags)
 {
 	int ret;
 
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
 		ret = report_syscall_entry(regs);
 		if (ret || (flags & _TIF_SYSCALL_EMU))
-			return NO_SYSCALL;
+			return false;
 
 		/* ptrace might have changed thread flags */
 		flags = read_thread_flags();
@@ -2486,7 +2486,7 @@ int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags)
 	/* Do the secure computing after ptrace; failures should be fast. */
 	if (unlikely(flags & _TIF_SECCOMP)) {
 		if (!__seccomp_permit_syscall())
-			return NO_SYSCALL;
+			return false;
 	}
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
@@ -2495,7 +2495,7 @@ int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags)
 	if (unlikely(audit_context()))
 		syscall_enter_audit(regs);
 
-	return syscall_get_nr(current, regs);
+	return true;
 }
 
 static inline bool report_single_step(unsigned long flags)
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 3488afd45d20..72c6e8b7ab21 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -108,7 +108,11 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		scno = arm64_syscall_trace_enter(regs, read_thread_flags());
+		if (!arm64_syscall_trace_enter(regs, read_thread_flags()))
+			goto trace_exit;
+
+		/* Reread the syscall number as it might have been modified */
+		scno = syscall_get_nr(current, regs);
 		if (scno == NO_SYSCALL)
 			goto trace_exit;
 	}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 13/15] arm64: entry: Convert to generic entry
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (11 preceding siblings ...)
  2026-09-30 10:18 ` [PATCH v20 12/15] arm64: ptrace: Make return type of arm64_syscall_trace_enter() bool Jinjie Ruan
@ 2026-09-30 10:18 ` Jinjie Ruan
  2026-09-30 10:18 ` [PATCH v20 14/15] arm64: Inline el0_svc_common() Jinjie Ruan
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:18 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

Implement the generic entry framework for arm64 to handle system call
entry and exit. This follows the migration of x86, RISC-V, and LoongArch,
consolidating architecture-specific syscall tracing and auditing into
the common kernel entry infrastructure, making it easier to enable
advanced features on arm64, such as "Syscall User Dispatch" and "rseq time
slice extension" optimization.

[Background]
Arm64 has already adopted generic IRQ entry. Completing the conversion
to the generic syscall entry framework reduces architectural divergence,
simplifies maintenance, and allows arm64 to automatically benefit from
improvements in the common entry code.

[Changes]

1. Kconfig and Infrastructure:
- Select GENERIC_ENTRY and remove GENERIC_IRQ_ENTRY (now implied).

- Migrate struct thread_info to use the syscall_work field instead
  of TIF flags for syscall-related tasks.

2. Thread Info and Flags:
- Remove definitions for TIF_SYSCALL_TRACE, TIF_SYSCALL_AUDIT,
  TIF_SYSCALL_TRACEPOINT, TIF_SECCOMP, and TIF_SYSCALL_EMU.

- Replace _TIF_SYSCALL_WORK and _TIF_SYSCALL_EXIT_WORK with the
  generic SYSCALL_WORK bitmask.

- Map single-step state to SYSCALL_EXIT_TRAP in debug-monitors.c.

3. Architecture-Specific Hooks (asm/entry-common.h): Implement following
  arch function by porting the existing arm64 logic to the generic
  interface:
  - arch_ptrace_report_syscall_permit_entry()
  - arch_ptrace_report_syscall_exit()

4. Cleanup and Refactoring: Remove redundant arm64-specific syscall
  tracing functions from ptrace.c, including following key functions
  and related audit/step helpers:
  - arm64_syscall_exit_to_user_mode_work()
  - arm64_syscall_trace_enter()
  - arm64_syscall_exit_work().

- Update el0_svc_common() in syscall.c to use the generic
  syscall_work checks and entry/exit call sites.

[Why this matters]
- Unified Interface: Aligns arm64 with the modern kernel entry standard.

- Improved Maintainability: Bug fixes in kernel/entry/common.c now
  apply to arm64 automatically.

- Feature Readiness: Simplifies the implementation of future
  cross-architecture syscall features.

[Compatibility]
This conversion maintains full ABI compatibility with existing
userspace. The ptrace register-saving behavior, seccomp filtering,
and syscall tracing semantics remain identical to the previous
implementation.

The set of traceable functions on the syscall path does change, though
this is not ABI.  Removed: syscall_trace_enter(), syscall_trace_exit()
and el0_svc_common.constprop.0.  Added: trace_syscall_enter(),
trace_syscall_exit() and syscall_enter_audit().  The new names are the
same ones x86, RISC-V, LoongArch and s390 already expose.

Note that Syscall User Dispatch and the rseq time slice extension are
still not enabled on arm64 by this series: they additionally require
ARCH_SUPPORTS_SYSCALL_USER_DISPATCH and HAVE_GENERIC_TIF_BITS
respectively, neither of which arm64 selects yet.

Additionally, since arm64 now does not select HAVE_GENERIC_TIF_BITS, there
is no functional change regarding rseq management, as those generic entry
pathways remain a no-op for this architecture.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Thomas Gleixner <tglx@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Tested-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Suggested-by: Kevin Brodsky <kevin.brodsky@arm.com>
Suggested-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Kees Cook <kees@kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/Kconfig                    |   2 +-
 arch/arm64/include/asm/entry-common.h |  77 ++++++++++++++
 arch/arm64/include/asm/syscall.h      |  14 ---
 arch/arm64/include/asm/thread_info.h  |  19 +---
 arch/arm64/kernel/debug-monitors.c    |   8 ++
 arch/arm64/kernel/entry-common.c      |   2 +-
 arch/arm64/kernel/ptrace.c            | 138 --------------------------
 arch/arm64/kernel/signal.c            |   2 +-
 arch/arm64/kernel/syscall.c           |   9 +-
 9 files changed, 95 insertions(+), 176 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b5a51b0ef944..3de3f728f4d8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -129,9 +129,9 @@ config ARM64
 	select GENERIC_CPU_DEVICES
 	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_EARLY_IOREMAP
+	select GENERIC_ENTRY
 	select GENERIC_IDLE_POLL_SETUP
 	select GENERIC_IOREMAP
-	select GENERIC_IRQ_ENTRY
 	select GENERIC_IRQ_IPI
 	select GENERIC_IRQ_KEXEC_CLEAR_VM_FORWARD
 	select GENERIC_IRQ_PROBE
diff --git a/arch/arm64/include/asm/entry-common.h b/arch/arm64/include/asm/entry-common.h
index 1905765159aa..5fffa4347f5b 100644
--- a/arch/arm64/include/asm/entry-common.h
+++ b/arch/arm64/include/asm/entry-common.h
@@ -3,14 +3,21 @@
 #ifndef _ASM_ARM64_ENTRY_COMMON_H
 #define _ASM_ARM64_ENTRY_COMMON_H
 
+#include <linux/ptrace.h>
 #include <linux/thread_info.h>
 
+#include <asm/compat.h>
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/fpsimd.h>
 #include <asm/mte.h>
 #include <asm/stacktrace.h>
 
+enum ptrace_syscall_dir {
+	PTRACE_SYSCALL_ENTER = 0,
+	PTRACE_SYSCALL_EXIT,
+};
+
 #define ARCH_EXIT_TO_USER_MODE_WORK (_TIF_MTE_ASYNC_FAULT | _TIF_FOREIGN_FPSTATE)
 
 static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
@@ -54,4 +61,74 @@ static inline bool arch_irqentry_exit_need_resched(void)
 
 #define arch_irqentry_exit_need_resched arch_irqentry_exit_need_resched
 
+static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
+						     enum ptrace_syscall_dir dir,
+						     int *regno)
+{
+	unsigned long saved_reg;
+
+	/*
+	 * We have some ABI weirdness here in the way that we handle syscall
+	 * exit stops because we indicate whether or not the stop has been
+	 * signalled from syscall entry or syscall exit by clobbering a general
+	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
+	 * and restoring its old value after the stop. This means that:
+	 *
+	 * - Any writes by the tracer to this register during the stop are
+	 *   ignored/discarded.
+	 *
+	 * - The actual value of the register is not available during the stop,
+	 *   so the tracer cannot save it and restore it later.
+	 *
+	 * - Syscall stops behave differently to seccomp and pseudo-step traps
+	 *   (the latter do not nobble any registers).
+	 */
+	*regno = (is_compat_task() ? 12 : 7);
+	saved_reg = regs->regs[*regno];
+	regs->regs[*regno] = dir;
+
+	return saved_reg;
+}
+
+static __always_inline bool arch_ptrace_report_syscall_permit_entry(struct pt_regs *regs)
+{
+	unsigned long saved_reg;
+	bool permit;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
+	permit = ptrace_report_syscall_permit_entry(regs);
+	if (!permit)
+		forget_syscall(regs);
+	regs->regs[regno] = saved_reg;
+
+	return permit;
+}
+
+#define arch_ptrace_report_syscall_permit_entry arch_ptrace_report_syscall_permit_entry
+
+static __always_inline void arch_ptrace_report_syscall_exit(struct pt_regs *regs,
+							    int step)
+{
+	unsigned long saved_reg;
+	int regno;
+
+	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
+	if (!step) {
+		ptrace_report_syscall_exit(regs, 0);
+		regs->regs[regno] = saved_reg;
+	} else {
+		regs->regs[regno] = saved_reg;
+
+		/*
+		 * Signal a pseudo-step exception since we are stepping but
+		 * tracer modifications to the registers may have rewound the
+		 * state machine.
+		 */
+		ptrace_report_syscall_exit(regs, 1);
+	}
+}
+
+#define arch_ptrace_report_syscall_exit arch_ptrace_report_syscall_exit
+
 #endif /* _ASM_ARM64_ENTRY_COMMON_H */
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index f19d4a8824ba..e3e716575846 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -120,18 +120,4 @@ static inline int syscall_get_arch(struct task_struct *task)
 
 	return AUDIT_ARCH_AARCH64;
 }
-
-bool arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
-void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags);
-
-static __always_inline void arm64_syscall_exit_to_user_mode_work(struct pt_regs *regs)
-{
-	unsigned long flags = read_thread_flags();
-
-	rseq_syscall(regs);
-
-	if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
-		arm64_syscall_exit_work(regs, flags);
-}
-
 #endif	/* __ASM_SYSCALL_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 56a2c9426a32..3f621ba0f961 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -46,6 +46,7 @@ struct thread_info {
 	u64			mpam_partid_pmg;
 #endif
 	u32			cpu;
+	unsigned long		syscall_work;   /* SYSCALL_WORK_ flags */
 };
 
 #define thread_saved_pc(tsk)	\
@@ -68,11 +69,6 @@ void arch_setup_new_exec(void);
 #define TIF_UPROBE		5	/* uprobe breakpoint or singlestep */
 #define TIF_MTE_ASYNC_FAULT	6	/* MTE Asynchronous Tag Check Fault */
 #define TIF_NOTIFY_SIGNAL	7	/* signal notifications exist */
-#define TIF_SYSCALL_TRACE	8	/* syscall trace active */
-#define TIF_SYSCALL_AUDIT	9	/* syscall auditing */
-#define TIF_SYSCALL_TRACEPOINT	10	/* syscall tracepoint for ftrace */
-#define TIF_SECCOMP		11	/* syscall secure computing */
-#define TIF_SYSCALL_EMU		12	/* syscall emulation active */
 #define TIF_PATCH_PENDING	13	/* pending live patching update */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FREEZE		19
@@ -94,27 +90,14 @@ void arch_setup_new_exec(void);
 #define _TIF_NEED_RESCHED_LAZY	(1 << TIF_NEED_RESCHED_LAZY)
 #define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 #define _TIF_FOREIGN_FPSTATE	(1 << TIF_FOREIGN_FPSTATE)
-#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
-#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
-#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
-#define _TIF_SYSCALL_EMU	(1 << TIF_SYSCALL_EMU)
 #define _TIF_PATCH_PENDING	(1 << TIF_PATCH_PENDING)
 #define _TIF_UPROBE		(1 << TIF_UPROBE)
-#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
 #define _TIF_32BIT		(1 << TIF_32BIT)
 #define _TIF_SVE		(1 << TIF_SVE)
 #define _TIF_MTE_ASYNC_FAULT	(1 << TIF_MTE_ASYNC_FAULT)
 #define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 #define _TIF_TSC_SIGSEGV	(1 << TIF_TSC_SIGSEGV)
 
-#define _TIF_SYSCALL_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-				 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
-				 _TIF_SYSCALL_EMU)
-
-#define _TIF_SYSCALL_EXIT_WORK	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-				 _TIF_SYSCALL_TRACEPOINT)
-
 #ifdef CONFIG_SHADOW_CALL_STACK
 #define INIT_SCS							\
 	.scs_base	= init_shadow_call_stack,			\
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index e271fbac5f82..5da530034e2e 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -382,11 +382,19 @@ void user_enable_single_step(struct task_struct *task)
 
 	if (!test_and_set_ti_thread_flag(ti, TIF_SINGLESTEP))
 		set_regs_spsr_ss(task_pt_regs(task));
+
+	/*
+	 * Ensure that the generic entry code triggers a trap once stepping
+	 * out of a system call prior to executing any user instruction,
+	 * as the generic entry code does not natively check for TIF_SINGLESTEP.
+	 */
+	set_task_syscall_work(task, SYSCALL_EXIT_TRAP);
 }
 NOKPROBE_SYMBOL(user_enable_single_step);
 
 void user_disable_single_step(struct task_struct *task)
 {
 	clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP);
+	clear_task_syscall_work(task, SYSCALL_EXIT_TRAP);
 }
 NOKPROBE_SYMBOL(user_disable_single_step);
diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index 72c03ccea59f..e8b750a962e8 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -6,7 +6,7 @@
  */
 
 #include <linux/context_tracking.h>
-#include <linux/irq-entry-common.h>
+#include <linux/entry-common.h>
 #include <linux/kasan.h>
 #include <linux/linkage.h>
 #include <linux/livepatch.h>
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index c304c062abbb..df3b0d343d7d 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -8,7 +8,6 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 
-#include <linux/audit.h>
 #include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/sched/signal.h>
@@ -18,7 +17,6 @@
 #include <linux/smp.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/seccomp.h>
 #include <linux/security.h>
 #include <linux/init.h>
 #include <linux/signal.h>
@@ -37,13 +35,9 @@
 #include <asm/mte.h>
 #include <asm/pointer_auth.h>
 #include <asm/stacktrace.h>
-#include <asm/syscall.h>
 #include <asm/traps.h>
 #include <asm/system_misc.h>
 
-#define CREATE_TRACE_POINTS
-#include <trace/events/syscalls.h>
-
 struct pt_regs_offset {
 	const char *name;
 	int offset;
@@ -2388,138 +2382,6 @@ long arch_ptrace(struct task_struct *child, long request,
 	return ptrace_request(child, request, addr, data);
 }
 
-enum ptrace_syscall_dir {
-	PTRACE_SYSCALL_ENTER = 0,
-	PTRACE_SYSCALL_EXIT,
-};
-
-static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs,
-						     enum ptrace_syscall_dir dir,
-						     int *regno)
-{
-	unsigned long saved_reg;
-
-	/*
-	 * We have some ABI weirdness here in the way that we handle syscall
-	 * exit stops because we indicate whether or not the stop has been
-	 * signalled from syscall entry or syscall exit by clobbering a general
-	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
-	 * and restoring its old value after the stop. This means that:
-	 *
-	 * - Any writes by the tracer to this register during the stop are
-	 *   ignored/discarded.
-	 *
-	 * - The actual value of the register is not available during the stop,
-	 *   so the tracer cannot save it and restore it later.
-	 *
-	 * - Syscall stops behave differently to seccomp and pseudo-step traps
-	 *   (the latter do not nobble any registers).
-	 */
-	*regno = (is_compat_task() ? 12 : 7);
-	saved_reg = regs->regs[*regno];
-	regs->regs[*regno] = dir;
-
-	return saved_reg;
-}
-
-static int report_syscall_entry(struct pt_regs *regs)
-{
-	unsigned long saved_reg;
-	int regno, ret;
-
-	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, &regno);
-	ret = !ptrace_report_syscall_permit_entry(regs);
-	if (ret)
-		forget_syscall(regs);
-	regs->regs[regno] = saved_reg;
-
-	return ret;
-}
-
-static void report_syscall_exit(struct pt_regs *regs)
-{
-	unsigned long saved_reg;
-	int regno;
-
-	saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, &regno);
-	if (!test_thread_flag(TIF_SINGLESTEP)) {
-		ptrace_report_syscall_exit(regs, 0);
-		regs->regs[regno] = saved_reg;
-	} else {
-		regs->regs[regno] = saved_reg;
-
-		/*
-		 * Signal a pseudo-step exception since we are stepping but
-		 * tracer modifications to the registers may have rewound the
-		 * state machine.
-		 */
-		ptrace_report_syscall_exit(regs, 1);
-	}
-}
-
-#ifdef CONFIG_AUDITSYSCALL
-static inline void syscall_enter_audit(struct pt_regs *regs)
-{
-	long syscall = syscall_get_nr(current, regs);
-	unsigned long args[6];
-
-	syscall_get_arguments(current, regs, args);
-	__audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
-}
-#else
-static inline void syscall_enter_audit(struct pt_regs *regs) { }
-#endif
-
-bool arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags)
-{
-	int ret;
-
-	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
-		ret = report_syscall_entry(regs);
-		if (ret || (flags & _TIF_SYSCALL_EMU))
-			return false;
-
-		/* ptrace might have changed thread flags */
-		flags = read_thread_flags();
-	}
-
-	/* Do the secure computing after ptrace; failures should be fast. */
-	if (unlikely(flags & _TIF_SECCOMP)) {
-		if (!__seccomp_permit_syscall())
-			return false;
-	}
-
-	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
-		trace_sys_enter(regs, syscall_get_nr(current, regs));
-
-	if (unlikely(audit_context()))
-		syscall_enter_audit(regs);
-
-	return true;
-}
-
-static inline bool report_single_step(unsigned long flags)
-{
-	if (flags & _TIF_SYSCALL_EMU)
-		return false;
-
-	return flags & _TIF_SINGLESTEP;
-}
-
-void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags)
-{
-	bool step;
-
-	audit_syscall_exit(regs);
-
-	if (flags & _TIF_SYSCALL_TRACEPOINT)
-		trace_sys_exit(regs, syscall_get_return_value(current, regs));
-
-	step = report_single_step(flags);
-	if (step || flags & _TIF_SYSCALL_TRACE)
-		report_syscall_exit(regs);
-}
-
 /*
  * SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a.
  * We permit userspace to set SSBS (AArch64 bit 12, AArch32 bit 23) which is
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 38e6fa204c17..093eebb9d764 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -8,8 +8,8 @@
 
 #include <linux/cache.h>
 #include <linux/compat.h>
+#include <linux/entry-common.h>
 #include <linux/errno.h>
-#include <linux/irq-entry-common.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/freezer.h>
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 72c6e8b7ab21..4a13108defb0 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -2,6 +2,7 @@
 
 #include <linux/compiler.h>
 #include <linux/context_tracking.h>
+#include <linux/entry-common.h>
 #include <linux/errno.h>
 #include <linux/nospec.h>
 #include <linux/ptrace.h>
@@ -58,6 +59,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 			   const syscall_fn_t syscall_table[])
 {
 	unsigned long flags = read_thread_flags();
+	unsigned long work;
 
 	regs->orig_x0 = regs->regs[0];
 	regs->syscallno = scno;
@@ -90,7 +92,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		return;
 	}
 
-	if (unlikely(flags & _TIF_SYSCALL_WORK)) {
+	work = READ_ONCE(current_thread_info()->syscall_work);
+	if (unlikely(work & SYSCALL_WORK_ENTER)) {
 		/*
 		 * The de-facto standard way to skip a system call using ptrace
 		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
@@ -108,7 +111,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 		 */
 		if (scno == NO_SYSCALL)
 			syscall_set_return_value(current, regs, -ENOSYS, 0);
-		if (!arm64_syscall_trace_enter(regs, read_thread_flags()))
+		if (!syscall_trace_enter(regs, work, scno))
 			goto trace_exit;
 
 		/* Reread the syscall number as it might have been modified */
@@ -119,7 +122,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 
 	invoke_syscall(regs, scno, sc_nr, syscall_table);
 trace_exit:
-	arm64_syscall_exit_to_user_mode_work(regs);
+	syscall_exit_to_user_mode_work(regs);
 }
 
 void do_el0_svc(struct pt_regs *regs)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 14/15] arm64: Inline el0_svc_common()
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (12 preceding siblings ...)
  2026-09-30 10:18 ` [PATCH v20 13/15] arm64: entry: Convert to generic entry Jinjie Ruan
@ 2026-09-30 10:18 ` Jinjie Ruan
  2026-09-30 10:18 ` [PATCH v20 15/15] selftests/arm64: Add ptrace SYSEMU/single-step tests Jinjie Ruan
  2026-10-26  8:52 ` [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:18 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

After converting arm64 to Generic Entry framework, the compiler no longer
inlines el0_svc_common() into its caller do_el0_svc(). This introduces
a small but measurable overhead in the critical system call path.

Manually forcing el0_svc_common() to be inlined restores the
performance. Benchmarking with perf bench syscall basic on a
Kunpeng 920 platform (based on v6.19-rc1) shows a ~1% performance
uplift.

Inlining this function reduces function prologue/epilogue overhead
and allows for better compiler optimization in the hot system call
dispatch path.

| Metric     | W/O this patch | With this patch | Change    |
| ---------- | -------------- | --------------- | --------- |
| Total time | 2.195 [sec]    | 2.171 [sec]     |  ↓1.1%   |
| usecs/op   | 0.219575       | 0.217192        |  ↓1.1%   |
| ops/sec    | 4,554,260      | 4,604,225       |  ↑1.1%    |

Two side effects of the inlining are worth noting:

- Syscall-path stack usage grows slightly.  do_el0_svc() now has a
  single 112-byte frame and 13 calls, where previously a 16-byte frame
  called a 48-byte el0_svc_common(); that is +48 bytes of stack on the
  syscall path.  lkdtm's KSTACK_ERASE confirms the 48-byte delta at
  runtime.

- The inlined code, together with the __always_inline generic
  entry/exit helpers, lands in .noinstr.text.  arm64 does not have
  objtool noinstr validation like x86, so this was checked directly on
  the built image: there are no __mcount_loc entries inside
  .noinstr.text, and the inlined syscall code calls no ftrace or
  sanitizer instrumentation.

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 arch/arm64/kernel/syscall.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 4a13108defb0..2535cae9413d 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -55,8 +55,8 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 	syscall_set_return_value(current, regs, 0, ret);
 }
 
-static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
-			   const syscall_fn_t syscall_table[])
+static __always_inline void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
+					   const syscall_fn_t syscall_table[])
 {
 	unsigned long flags = read_thread_flags();
 	unsigned long work;
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v20 15/15] selftests/arm64: Add ptrace SYSEMU/single-step tests
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (13 preceding siblings ...)
  2026-09-30 10:18 ` [PATCH v20 14/15] arm64: Inline el0_svc_common() Jinjie Ruan
@ 2026-09-30 10:18 ` Jinjie Ruan
  2026-10-26  8:52 ` [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-09-30 10:18 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest
  Cc: ruanjinjie

The ptrace man page requires that PTRACE_SYSEMU and
PTRACE_SYSEMU_SINGLESTEP do not produce a syscall-exit-stop as below:

	"If the tracee was restarted by PTRACE_SYSCALL or PTRACE_SYSEMU,
	the tracee enters syscall-enter-stop just prior to entering any
	system call (which will not be executed if the restart was using
	PTRACE_SYSEMU, regardless of any change made to registers at this
	point or how the tracee is restarted after this stop). ...
	If the tracee is continued using any other method (including
	PTRACE_SYSEMU), no syscall-exit-stop occurs. Note that all mentions
	PTRACE_SYSEMU apply equally to PTRACE_SYSEMU_SINGLESTEP."

And commit ac2081cdc4d9 ("arm64: ptrace: Consistently use
pseudo-singlestep exceptions") added the pseudo-step to avoid corrupt
the arm64 stepping state.

Add four tests covering arm64 syscall-exit pseudo-step and single-step
behaviour:
 - sysemu_singlestep_no_exit_stop: an emulated syscall has no
   syscall-exit-stop (ptrace(2))
 - sysemu_singlestep_intercept: the tracee is intercepted after an
   emulated syscall
 - single_step_signal_handler: single-stepping stops at the signal
   handler entry
 - single_step_syscall_stop: single-step survives a ptrace stop taken
   during a syscall

Link: https://lore.kernel.org/all/20200710130702.30658-1-will@kernel.org/
Assisted-by: DeepSeek:DeepSeek-v4 flash
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 tools/testing/selftests/arm64/Makefile        |   2 +-
 tools/testing/selftests/arm64/ptrace/Makefile |   9 ++
 .../selftests/arm64/ptrace/ptrace_common.h    |  84 +++++++++++
 .../arm64/ptrace/single_step_signal_handler.c | 131 ++++++++++++++++++
 .../arm64/ptrace/single_step_syscall_stop.c   | 130 +++++++++++++++++
 .../ptrace/sysemu_singlestep_intercept.c      |  93 +++++++++++++
 .../ptrace/sysemu_singlestep_no_exit_stop.c   |  81 +++++++++++
 7 files changed, 529 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/arm64/ptrace/Makefile
 create mode 100644 tools/testing/selftests/arm64/ptrace/ptrace_common.h
 create mode 100644 tools/testing/selftests/arm64/ptrace/single_step_signal_handler.c
 create mode 100644 tools/testing/selftests/arm64/ptrace/single_step_syscall_stop.c
 create mode 100644 tools/testing/selftests/arm64/ptrace/sysemu_singlestep_intercept.c
 create mode 100644 tools/testing/selftests/arm64/ptrace/sysemu_singlestep_no_exit_stop.c

diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index e456f3b62fa1..3edd476f8fc0 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -4,7 +4,7 @@
 ARCH ?= $(shell uname -m 2>/dev/null || echo not)
 
 ifneq (,$(filter $(ARCH),aarch64 arm64))
-ARM64_SUBTARGETS ?= tags signal pauth fp mte bti abi gcs
+ARM64_SUBTARGETS ?= tags signal pauth fp mte bti abi gcs ptrace
 else
 ARM64_SUBTARGETS :=
 endif
diff --git a/tools/testing/selftests/arm64/ptrace/Makefile b/tools/testing/selftests/arm64/ptrace/Makefile
new file mode 100644
index 000000000000..1feec905ab6e
--- /dev/null
+++ b/tools/testing/selftests/arm64/ptrace/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES)
+
+TEST_GEN_PROGS := sysemu_singlestep_no_exit_stop \
+		  sysemu_singlestep_intercept \
+		  single_step_signal_handler \
+		  single_step_syscall_stop
+
+include ../../lib.mk
diff --git a/tools/testing/selftests/arm64/ptrace/ptrace_common.h b/tools/testing/selftests/arm64/ptrace/ptrace_common.h
new file mode 100644
index 000000000000..4e4f7c67437c
--- /dev/null
+++ b/tools/testing/selftests/arm64/ptrace/ptrace_common.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Shared helpers for the arm64 ptrace self-tests.
+ */
+#ifndef ARM64_PTRACE_COMMON_H
+#define ARM64_PTRACE_COMMON_H
+
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <elf.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <linux/ptrace.h>
+#include <asm/ptrace.h>
+
+/* Program counter of the tracee (0 on failure). */
+static inline unsigned long tracee_pc(pid_t pid)
+{
+	struct iovec iov;
+	struct user_pt_regs regs;
+
+	iov.iov_base = &regs;
+	iov.iov_len = sizeof(regs);
+	if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &iov) < 0)
+		return 0;
+	return regs.pc;
+}
+
+/* PTRACE_SYSCALL_INFO_* op of the current stop, plus syscall nr on entry. */
+static inline int syscall_info(pid_t pid, long *nr)
+{
+	struct ptrace_syscall_info info;
+
+	memset(&info, 0, sizeof(info));
+	if (ptrace(PTRACE_GET_SYSCALL_INFO, pid, (void *)sizeof(info),
+		   &info) < 0)
+		return PTRACE_SYSCALL_INFO_NONE;
+	if (info.op == PTRACE_SYSCALL_INFO_ENTRY && nr)
+		*nr = (long)info.entry.nr;
+	return info.op;
+}
+
+static inline int traceme(void)
+{
+	return ptrace(PTRACE_TRACEME, 0, 0, 0);
+}
+
+/* Stop tracing the tracee and reap it so it does not linger as a zombie. */
+static inline void tracee_kill(pid_t pid)
+{
+	ptrace(PTRACE_KILL, pid, 0, 0);
+	waitpid(pid, NULL, 0);
+}
+
+/* Wall-clock guard so a broken kernel cannot hang the test run. */
+static volatile sig_atomic_t ptrace_timed_out;
+
+static void ptrace_timeout_handler(int sig)
+{
+	(void)sig;
+	ptrace_timed_out = 1;
+}
+
+static inline void ptrace_timeout_start(unsigned int seconds)
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = ptrace_timeout_handler;
+	sigemptyset(&sa.sa_mask);
+	sigaction(SIGALRM, &sa, NULL);
+	alarm(seconds);
+}
+
+static inline void ptrace_timeout_stop(void)
+{
+	alarm(0);
+}
+
+#endif /* ARM64_PTRACE_COMMON_H */
diff --git a/tools/testing/selftests/arm64/ptrace/single_step_signal_handler.c b/tools/testing/selftests/arm64/ptrace/single_step_signal_handler.c
new file mode 100644
index 000000000000..249a70058781
--- /dev/null
+++ b/tools/testing/selftests/arm64/ptrace/single_step_signal_handler.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Single-stepping into a signal handler must stop at the handler entry.
+ *
+ * When TIF_SINGLESTEP is set the kernel must arrange for the tracee to be
+ * stopped as it steps into a signal handler; leaving it to the hardware
+ * fast-forward would execute the first instruction of the handler before
+ * reporting it.
+ *
+ * (ac2081cdc4d9 "arm64: ptrace: Consistently use pseudo-singlestep
+ * exceptions")
+ */
+#include <sys/mman.h>
+
+#include "kselftest.h"
+#include "ptrace_common.h"
+
+static volatile unsigned long *sh;
+
+static void sigusr1_handler(int sig)
+{
+	(void)sig;
+	sh[1] = 1;
+}
+
+static bool steps_into_signal_handler(void)
+{
+	int status, deliver = 0, delivering = 0;
+	bool stepped_in = false, handler_ran = false;
+	bool ok = false;
+	pid_t child;
+
+	sh = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+		  MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	if (sh == MAP_FAILED)
+		return false;
+	sh[0] = 0;
+	sh[1] = 0;
+
+	child = fork();
+	if (child == 0) {
+		struct sigaction sa;
+		sigset_t blk;
+
+		memset(&sa, 0, sizeof(sa));
+		sa.sa_handler = sigusr1_handler;
+		sigemptyset(&sa.sa_mask);
+		sigaction(SIGUSR1, &sa, NULL);
+
+		sigemptyset(&blk);
+		sigaddset(&blk, SIGTRAP);
+		sigprocmask(SIG_BLOCK, &blk, NULL);
+
+		if (traceme() < 0)
+			_exit(3);
+		sh[0] = (unsigned long)sigusr1_handler;
+		raise(SIGSTOP);
+		while (!sh[1])
+			asm volatile("nop");
+		_exit(0);
+	}
+
+	if (waitpid(child, &status, 0) < 0)
+		return false;
+	ptrace(PTRACE_SETOPTIONS, child, 0, 0);
+
+	/* Queue the signal; it is delivered on the next resume. */
+	kill(child, SIGUSR1);
+	ptrace_timeout_start(60);
+
+	for (;;) {
+		int sig;
+		unsigned long pc;
+
+		if (ptrace_timed_out)
+			break;
+		if (ptrace(PTRACE_SINGLESTEP, child, 0,
+			   (void *)(long)deliver) < 0)
+			break;
+		deliver = 0;
+		if (waitpid(child, &status, 0) < 0)
+			break;
+		if (WIFEXITED(status) || WIFSIGNALED(status))
+			break;
+		if (!WIFSTOPPED(status))
+			continue;
+
+		sig = WSTOPSIG(status);
+		pc = tracee_pc(child);
+
+		if (sig == SIGUSR1) {
+			/* deliver it on the next resume */
+			deliver = SIGUSR1;
+			delivering = 1;
+			continue;
+		}
+		if (delivering) {
+			/* the kernel must stop at the handler entry */
+			if (sig != SIGTRAP || pc != sh[0])
+				break;
+			stepped_in = true;
+			delivering = 0;
+			continue;
+		}
+		if (stepped_in && sh[1]) {
+			/* the handler ran, so it was not reset to SIG_DFL */
+			handler_ran = true;
+			break;
+		}
+	}
+	ptrace_timeout_stop();
+	tracee_kill(child);
+
+	ok = stepped_in && handler_ran;
+	return ok;
+}
+
+int main(void)
+{
+	bool ok;
+
+	ksft_print_header();
+	ksft_set_plan(1);
+
+	ok = steps_into_signal_handler();
+	ksft_test_result(ok, "stopped at the signal handler entry\n");
+
+	if (ok)
+		ksft_exit_pass();
+	ksft_exit_fail();
+}
diff --git a/tools/testing/selftests/arm64/ptrace/single_step_syscall_stop.c b/tools/testing/selftests/arm64/ptrace/single_step_syscall_stop.c
new file mode 100644
index 000000000000..a44bdf6153e8
--- /dev/null
+++ b/tools/testing/selftests/arm64/ptrace/single_step_syscall_stop.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A ptrace stop taken during a system call (here a seccomp RET_TRACE trap)
+ * must not lose the single-step stop at syscall exit, even if the tracer
+ * modifies the tracee's registers at that stop.
+ *
+ * This covers the second issue fixed by ac2081cdc4d9 ("arm64: ptrace:
+ * Consistently use pseudo-singlestep exceptions"): the hardware
+ * fast-forwards the software-step state machine across the SVC, and the
+ * ptrace stop during the syscall may rewind it.
+ */
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+
+#include "kselftest.h"
+#include "ptrace_common.h"
+
+static int install_seccomp_getpid_trace(void)
+{
+	struct sock_filter filter[] = {
+		BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
+			 offsetof(struct seccomp_data, nr)),
+		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_getpid, 0, 1),
+		BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRACE),
+		BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
+	};
+	struct sock_fprog prog = {
+		.len = (unsigned short)ARRAY_SIZE(filter),
+		.filter = filter,
+	};
+
+	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
+		return -1;
+	return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+}
+
+static void poke_a_register(pid_t pid)
+{
+	struct user_pt_regs regs;
+	struct iovec iov;
+
+	iov.iov_base = &regs;
+	iov.iov_len = sizeof(regs);
+	if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &iov) == 0) {
+		regs.regs[0] ^= 1;
+		ptrace(PTRACE_SETREGSET, pid, (void *)NT_PRSTATUS, &iov);
+	}
+}
+
+static bool step_survives_stop_during_syscall(void)
+{
+	volatile int *marker;
+	pid_t child;
+	int status, seen_seccomp = 0;
+	bool ok = false;
+
+	marker = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+		      MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	if (marker == MAP_FAILED)
+		return false;
+	*marker = 0;
+
+	child = fork();
+	if (child == 0) {
+		if (traceme() < 0)
+			_exit(3);
+		raise(SIGSTOP);
+		if (install_seccomp_getpid_trace() < 0)
+			_exit(2);
+		(void)syscall(SYS_getpid);	/* seccomp RET_TRACE trap */
+		*marker = 1;			/* next instruction */
+		_exit(0);
+	}
+
+	if (waitpid(child, &status, 0) < 0)
+		return false;
+	if (WIFEXITED(status))
+		return false;
+	ptrace(PTRACE_SETOPTIONS, child, 0, (void *)PTRACE_O_TRACESECCOMP);
+	ptrace_timeout_start(60);
+
+	for (;;) {
+		if (ptrace_timed_out)
+			break;
+		if (ptrace(PTRACE_SINGLESTEP, child, 0, 0) < 0)
+			break;
+		if (waitpid(child, &status, 0) < 0)
+			break;
+		if (WIFEXITED(status) || WIFSIGNALED(status))
+			break;
+		if (!WIFSTOPPED(status))
+			continue;
+
+		if ((status >> 8) ==
+		    (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) {
+			seen_seccomp = 1;
+			poke_a_register(child);
+			continue;
+		}
+		if (seen_seccomp) {
+			/* first stop after the syscall, before the marker */
+			ok = (*marker == 0);
+			break;
+		}
+	}
+	ptrace_timeout_stop();
+	tracee_kill(child);
+
+	return ok;
+}
+
+int main(void)
+{
+	bool ok;
+
+	ksft_print_header();
+	ksft_set_plan(1);
+
+	ok = step_survives_stop_during_syscall();
+	ksft_test_result(ok, "single-step survives a ptrace stop during syscall\n");
+
+	if (ok)
+		ksft_exit_pass();
+	ksft_exit_fail();
+}
diff --git a/tools/testing/selftests/arm64/ptrace/sysemu_singlestep_intercept.c b/tools/testing/selftests/arm64/ptrace/sysemu_singlestep_intercept.c
new file mode 100644
index 000000000000..6d9900209d41
--- /dev/null
+++ b/tools/testing/selftests/arm64/ptrace/sysemu_singlestep_intercept.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * After an emulated system call, the tracee must be intercepted by a
+ * single-step stop before it executes the next instruction.  This guards
+ * against the software-step state machine being lost around the SVC.
+ */
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#include "kselftest.h"
+#include "ptrace_common.h"
+
+static bool intercepted_after_emulated_syscall(void)
+{
+	volatile int *marker;
+	pid_t child;
+	int status, phase = 0;
+	bool intercepted = false;
+
+	marker = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+		      MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	if (marker == MAP_FAILED)
+		return false;
+	*marker = 0;
+
+	child = fork();
+	if (child == 0) {
+		if (traceme() < 0)
+			_exit(3);
+		raise(SIGSTOP);
+		(void)syscall(SYS_getpid);	/* emulated syscall */
+		*marker = 1;			/* next instruction */
+		(void)syscall(SYS_getpid);	/* endpoint */
+		_exit(0);
+	}
+
+	if (waitpid(child, &status, 0) < 0)
+		return false;
+	ptrace(PTRACE_SETOPTIONS, child, 0, (void *)PTRACE_O_TRACESYSGOOD);
+	ptrace_timeout_start(60);
+
+	for (;;) {
+		long nr = -1;
+		int op;
+
+		if (ptrace_timed_out)
+			break;
+		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, child, 0, 0) < 0)
+			break;
+		if (waitpid(child, &status, 0) < 0)
+			break;
+		if (WIFEXITED(status))
+			break;
+		if (!WIFSTOPPED(status))
+			continue;
+
+		op = syscall_info(child, &nr);
+
+		if (op == PTRACE_SYSCALL_INFO_ENTRY && nr == SYS_getpid &&
+		    phase == 0) {
+			/* reached the emulated syscall, resume once */
+			phase = 1;
+			continue;
+		}
+
+		if (phase == 1) {
+			/* First stop after the emulated syscall: the marker
+			 * must not have run yet, i.e. the step was delivered.
+			 */
+			intercepted = (*marker == 0);
+			break;
+		}
+	}
+	ptrace_timeout_stop();
+	tracee_kill(child);
+
+	return intercepted;
+}
+
+int main(void)
+{
+	bool ok;
+
+	ksft_print_header();
+	ksft_set_plan(1);
+
+	ok = intercepted_after_emulated_syscall();
+	ksft_test_result(ok, "tracee intercepted after the emulated syscall\n");
+
+	if (ok)
+		ksft_exit_pass();
+	ksft_exit_fail();
+}
diff --git a/tools/testing/selftests/arm64/ptrace/sysemu_singlestep_no_exit_stop.c b/tools/testing/selftests/arm64/ptrace/sysemu_singlestep_no_exit_stop.c
new file mode 100644
index 000000000000..c5a0218b0c6c
--- /dev/null
+++ b/tools/testing/selftests/arm64/ptrace/sysemu_singlestep_no_exit_stop.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * An emulated system call (PTRACE_SYSEMU_SINGLESTEP) must report a
+ * syscall-enter-stop but no syscall-exit-stop, as documented in ptrace(2):
+ *
+ *	"If the tracee was restarted by PTRACE_SYSCALL or PTRACE_SYSEMU,
+ *	 the tracee enters syscall-enter-stop just prior to entering any
+ *	 system call ... If the tracee is continued using any other method
+ *	 (including PTRACE_SYSEMU), no syscall-exit-stop occurs."
+ */
+#include <sys/syscall.h>
+
+#include "kselftest.h"
+#include "ptrace_common.h"
+
+static bool emulated_syscall_has_no_exit_stop(void)
+{
+	pid_t child;
+	int status, after = -1;
+	bool saw_entry = false, saw_exit = false;
+
+	child = fork();
+	if (child == 0) {
+		if (traceme() < 0)
+			_exit(3);
+		raise(SIGSTOP);
+		(void)syscall(SYS_getpid);
+		_exit(0);
+	}
+
+	if (waitpid(child, &status, 0) < 0)
+		return false;
+	ptrace(PTRACE_SETOPTIONS, child, 0, (void *)PTRACE_O_TRACESYSGOOD);
+	ptrace_timeout_start(60);
+
+	for (;;) {
+		long nr = -1;
+		int op;
+
+		if (ptrace_timed_out)
+			break;
+		if (ptrace(PTRACE_SYSEMU_SINGLESTEP, child, 0, 0) < 0)
+			break;
+		if (waitpid(child, &status, 0) < 0)
+			break;
+		if (WIFEXITED(status))
+			break;
+		if (!WIFSTOPPED(status))
+			continue;
+
+		op = syscall_info(child, &nr);
+		if (op == PTRACE_SYSCALL_INFO_ENTRY) {
+			saw_entry = true;
+			if (nr == SYS_getpid && after < 0)
+				after = 4;
+		}
+		if (op == PTRACE_SYSCALL_INFO_EXIT)
+			saw_exit = true;
+		if (after > 0 && --after == 0)
+			break;
+	}
+	ptrace_timeout_stop();
+	tracee_kill(child);
+
+	return saw_entry && !saw_exit;
+}
+
+int main(void)
+{
+	bool ok;
+
+	ksft_print_header();
+	ksft_set_plan(1);
+
+	ok = emulated_syscall_has_no_exit_stop();
+	ksft_test_result(ok, "emulated syscall has no syscall-exit-stop\n");
+
+	if (ok)
+		ksft_exit_pass();
+	ksft_exit_fail();
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v20 00/15] arm64: entry: Convert to Generic Entry
  2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
                   ` (14 preceding siblings ...)
  2026-09-30 10:18 ` [PATCH v20 15/15] selftests/arm64: Add ptrace SYSEMU/single-step tests Jinjie Ruan
@ 2026-10-26  8:52 ` Jinjie Ruan
  15 siblings, 0 replies; 17+ messages in thread
From: Jinjie Ruan @ 2026-10-26  8:52 UTC (permalink / raw)
  To: catalin.marinas, will, mark.rutland, oleg, shuah, kees, luto,
	wad, peterz, ada.coupriediaz, linusw, kevin.brodsky, yeoreum.yun,
	james.morse, thuth, tglx, vladimir.murzin, broonie, ryan.roberts,
	liqiang01, linux-arm-kernel, linux-kernel, linux-kselftest



在 2026/9/30 18:17, Jinjie Ruan 写道:
> This series converts arm64 to the generic entry infrastructure.
> 
> Currently, architectures such as x86, RISC-V, LoongArch, PowerPC
> and s390 use generic entry, which significantly reduces maintenance
> burden and improves code elegance.  arm64 already adopted generic IRQ
> entry in commit b3cf07851b6c ("arm64: entry: Switch to generic IRQ entry"),
> making it the right time to complete the conversion.
> 
> This work brings arm64 in line with other major architectures,
> reducing duplicated code and enabling future improvements like
> Syscall User Dispatch and rseq time slice extension optimizations.
> 
> The series is rebased on v7.3-rc4 and has been tested with stress-ng,
> hackbench, kselftests (ptrace, breakpoints, arm64/abi, arm64/fp, vDSO),
> ptrace stress test, Pseudo-NMI load test, and the rr test suite [1].

Hi Mark and all,

Ping.

Are there any further review comments or new suggestions for changes?
I’m happy to address anything that comes up.

Thanks!
Jinjie

> 
> A new kselftest ("selftests/arm64: Add ptrace SYSEMU/single-step tests")
> is included at the end of the series, covering the syscall-exit
> pseudo-step and single-step behaviour touched by this work.
> 
> Observable (non-ABI) changes worth calling out:
> 
> - The traceable functions on the syscall path change: syscall_trace_enter,
>   syscall_trace_exit and el0_svc_common.constprop.0 are replaced by
>   trace_syscall_enter, trace_syscall_exit and syscall_enter_audit, the
>   same names x86, RISC-V, LoongArch and s390 already expose.
> 
> - CONFIG_DEBUG_RSEQ becomes unselectable on arm64 once GENERIC_ENTRY is
>   set (rseq_syscall() becomes a no-op stub), so the earlier rseq_syscall()
>   reordering is only temporary and the equivalent is handled by
>   __rseq_debug_syscall_return().
> 
> On gVisor with systrap mode, the Syscall User Dispatch (SUD) feature
> yields a slightly lower performance gain on arm64 (3% ~ 5%), similar to
> that on x86 [2].
> 
> Result: the average over 1M getpid calls, ns/op
> 
> 	| KVM VM Configuration | SUD    | no-SUD | Savings % |
> 	| -------------------  | -----  | -------| --------- |
> 	| 2 vCPU, pinned       | 4269.8 | 4509.5 | 5.3%      |
> 	| 4 vCPU, pinned       | 4175.4 | 4369.1 | 4.4%      |
> 	| 8 vCPU, pinned       | 4352.6 | 4485.4 | 3.0%      |
> 
> Note that this series does not yet enable SUD or the rseq time slice
> extension on arm64: SUD additionally needs
> ARCH_SUPPORTS_SYSCALL_USER_DISPATCH [3] and the rseq slice extension needs
> HAVE_GENERIC_TIF_BITS [4], neither of which arm64 selects today.  The
> numbers above are the motivation for enabling them in a follow-up.
> 
> Testing follow-up that still requires real hardware:
> 
> - MTE: run the MTE selftests on real hardware; part of them do not run
>   under QEMU.
> 
> [1]: https://github.com/rr-debugger/rr/wiki/Building-And-Installing#tests
> [2]: https://github.com/google/gvisor/commit/a45d6227b521012109cde9a942d644d778eb773b
> [3]: https://lore.kernel.org/all/20260721081858.1169276-16-ruanjinjie@huawei.com/
> [4]: https://lore.kernel.org/all/20260320104222.1381274-1-ruanjinjie@huawei.com/
> 
> Changes in v20:
> - Add a kselftest covering the syscall-exit pseudo-step
>   and single-step behaviour.
> - Reword the first patch: it skips the pseudo-step for the emulated
>   syscall rather than "fixing a redundant exit stop", and drop the
>   Fixes: tag and Reviewed-by.
> - Add Tested-by.
> - Cover letter: document the observable changes and the testing
>   follow-ups.
> - Link to v19: https://lore.kernel.org/all/20260922035510.1090299-1-ruanjinjie@huawei.com/
> 
> Changes in v19:
> - Rebased on v7.3-rc4.
> - Fix build problem as Karl pointed out.
> - Remove has_syscall_work() later to make it more clear.
> - Add gvisor test data.
> - Link to v18: https://lore.kernel.org/all/20260902095537.602517-2-ruanjinjie@huawei.com/
> 
> Changes in v18:
> - Rebased on v7.3-rc1.
> - Drop the SUD patch as Mark suggeted.
> - Update the commit message.
> - Add Reviewed-by.
> - Link to v17: https://lore.kernel.org/all/20260721081858.1169276-1-ruanjinjie@huawei.com/
> 
> For changes in v7 to v16, please refer to the individual patch threads:
> - v16: https://lore.kernel.org/all/20260629130616.642022-1-ruanjinjie@huawei.com/
> - v15: https://lore.kernel.org/all/20260511092103.1974980-1-ruanjinjie@huawei.com/
> - v14: https://lore.kernel.org/all/20260320102620.1336796-1-ruanjinjie@huawei.com/
> - v13: https://lore.kernel.org/all/20260317082020.737779-1-ruanjinjie@huawei.com/
> - v12: https://lore.kernel.org/all/20260203133728.848283-1-ruanjinjie@huawei.com/
> - v11: https://lore.kernel.org/all/20260128031934.3906955-1-ruanjinjie@huawei.com/
> - v10: https://lore.kernel.org/all/20251222114737.1334364-1-ruanjinjie@huawei.com/
> - v9: https://lore.kernel.org/all/20251204082123.2792067-1-ruanjinjie@huawei.com/
> - v8: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie@huawei.com/
> - v7: https://lore.kernel.org/all/20251117133048.53182-1-ruanjinjie@huawei.com/
> 
> 
> 
> Jinjie Ruan (15):
>   arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP
>   arm64: ptrace: Rework audit_syscall_entry()
>   arm64: ptrace: Open-code seccomp check in syscall_trace_enter()
>   arm64: ptrace: Rename and clean up syscall_trace_enter()
>   arm64: ptrace: Protect rseq_syscall() from tracer PC modifications
>   arm64: syscall: Rework the syscall exit path in el0_svc_common()
>   arm64: ptrace: Pass thread flags to trace enter/exit
>   arm64: ptrace: Extract arm64_syscall_exit_to_user_mode_work() helper
>   arm64: ptrace: Align syscall exit work semantics with generic entry
>   arm64: syscall: Use exit-specific flags check in el0_svc_common()
>   arm64: syscall: Simplify el0_svc_common() syscall exit path
>   arm64: ptrace: Make return type of arm64_syscall_trace_enter() bool
>   arm64: entry: Convert to generic entry
>   arm64: Inline el0_svc_common()
>   selftests/arm64: Add ptrace SYSEMU/single-step tests
> 
>  arch/arm64/Kconfig                            |   2 +-
>  arch/arm64/include/asm/entry-common.h         |  77 ++++++++++
>  arch/arm64/include/asm/syscall.h              |   5 +-
>  arch/arm64/include/asm/thread_info.h          |  16 +--
>  arch/arm64/kernel/debug-monitors.c            |   8 ++
>  arch/arm64/kernel/entry-common.c              |   2 +-
>  arch/arm64/kernel/ptrace.c                    | 115 ---------------
>  arch/arm64/kernel/signal.c                    |   2 +-
>  arch/arm64/kernel/syscall.c                   |  34 ++---
>  tools/testing/selftests/arm64/Makefile        |   2 +-
>  tools/testing/selftests/arm64/ptrace/Makefile |   9 ++
>  .../selftests/arm64/ptrace/ptrace_common.h    |  84 +++++++++++
>  .../arm64/ptrace/single_step_signal_handler.c | 131 ++++++++++++++++++
>  .../arm64/ptrace/single_step_syscall_stop.c   | 130 +++++++++++++++++
>  .../ptrace/sysemu_singlestep_intercept.c      |  93 +++++++++++++
>  .../ptrace/sysemu_singlestep_no_exit_stop.c   |  81 +++++++++++
>  16 files changed, 631 insertions(+), 160 deletions(-)
>  create mode 100644 tools/testing/selftests/arm64/ptrace/Makefile
>  create mode 100644 tools/testing/selftests/arm64/ptrace/ptrace_common.h
>  create mode 100644 tools/testing/selftests/arm64/ptrace/single_step_signal_handler.c
>  create mode 100644 tools/testing/selftests/arm64/ptrace/single_step_syscall_stop.c
>  create mode 100644 tools/testing/selftests/arm64/ptrace/sysemu_singlestep_intercept.c
>  create mode 100644 tools/testing/selftests/arm64/ptrace/sysemu_singlestep_no_exit_stop.c
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-10-26  8:52 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-30 10:17 [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 01/15] arm64: ptrace: Drop redundant pseudo-single-step for SYSEMU_SINGLESTEP Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 02/15] arm64: ptrace: Rework audit_syscall_entry() Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 03/15] arm64: ptrace: Open-code seccomp check in syscall_trace_enter() Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 04/15] arm64: ptrace: Rename and clean up syscall_trace_enter() Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 05/15] arm64: ptrace: Protect rseq_syscall() from tracer PC modifications Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 06/15] arm64: syscall: Rework the syscall exit path in el0_svc_common() Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 07/15] arm64: ptrace: Pass thread flags to trace enter/exit Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 08/15] arm64: ptrace: Extract arm64_syscall_exit_to_user_mode_work() helper Jinjie Ruan
2026-09-30 10:17 ` [PATCH v20 09/15] arm64: ptrace: Align syscall exit work semantics with generic entry Jinjie Ruan
2026-09-30 10:18 ` [PATCH v20 10/15] arm64: syscall: Use exit-specific flags check in el0_svc_common() Jinjie Ruan
2026-09-30 10:18 ` [PATCH v20 11/15] arm64: syscall: Simplify el0_svc_common() syscall exit path Jinjie Ruan
2026-09-30 10:18 ` [PATCH v20 12/15] arm64: ptrace: Make return type of arm64_syscall_trace_enter() bool Jinjie Ruan
2026-09-30 10:18 ` [PATCH v20 13/15] arm64: entry: Convert to generic entry Jinjie Ruan
2026-09-30 10:18 ` [PATCH v20 14/15] arm64: Inline el0_svc_common() Jinjie Ruan
2026-09-30 10:18 ` [PATCH v20 15/15] selftests/arm64: Add ptrace SYSEMU/single-step tests Jinjie Ruan
2026-10-26  8:52 ` [PATCH v20 00/15] arm64: entry: Convert to Generic Entry Jinjie Ruan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®