* [PATCH 01/14] alpha: fix saved registers in page-fault oops dumps
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 02/14] alpha: report syscall errors correctly to audit Magnus Lindholm
` (12 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
The aligned exception frame moved r9-r15 back by one word. Adjust the
pointer passed to die_if_kernel() so s0-s6 show the correct registers.
Fixes: 3b35a171060f ("alpha: align stack for page fault and user unaligned trap handlers")
Cc: stable@vger.kernel.org
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/mm/fault.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index 3dfeb854f196387d8c8f709d0ce355e5145035fb..f09f69894cfd65d814ab1cf498c946043fb9e8a3 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -244,7 +244,7 @@ retry:
terminate things with extreme prejudice. */
printk(KERN_ALERT "Unable to handle kernel paging request at "
"virtual address %016lx\n", address);
- die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
+ die_if_kernel("Oops", regs, cause, (unsigned long *)regs - 17);
make_task_dead(SIGKILL);
/* We ran out of memory, or some other thing happened to us that
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 02/14] alpha: report syscall errors correctly to audit
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
2026-11-03 21:35 ` [PATCH 01/14] alpha: fix saved registers in page-fault oops dumps Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 03/14] alpha: preserve rolled-back registers for SIGSYS Magnus Lindholm
` (11 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7, stable
Use a3 to distinguish errors from successful return values and negate
error codes for audit. Failed syscalls otherwise appear successful with
a positive errno. Keep raw r0 for kernel-mode frames.
Fixes: a9302e843944 ("alpha: Enable system-call auditing support.")
Cc: stable@vger.kernel.org
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/ptrace.h | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index 45d1229344b6f848eb930917bf50ba759da99beb..c933c8805eedd91e3845bb4b46588974258398c2 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -21,9 +21,18 @@
(current_thread_info()->syscall_meta \
|= ALPHA_SYSCALL_META_FORCE_SUCCESS)
-static inline unsigned long regs_return_value(struct pt_regs *regs)
+#define is_syscall_success is_syscall_success
+static inline int is_syscall_success(struct pt_regs *regs)
{
- return regs->r0;
+ return !regs->r19;
+}
+
+static inline long regs_return_value(struct pt_regs *regs)
+{
+ /* For user-mode registers, a3 is an error flag only at syscall exit. */
+ if (is_syscall_success(regs) || !user_mode(regs))
+ return regs->r0;
+ return -regs->r0;
}
unsigned long user_stack_pointer(struct pt_regs *regs);
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 03/14] alpha: preserve rolled-back registers for SIGSYS
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
2026-11-03 21:35 ` [PATCH 01/14] alpha: fix saved registers in page-fault oops dumps Magnus Lindholm
2026-11-03 21:35 ` [PATCH 02/14] alpha: report syscall errors correctly to audit Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 04/14] alpha: fix syscall restart eligibility Magnus Lindholm
` (10 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Record syscall_rollback() in syscall_meta so skipped-syscall handling
preserves r0 and a3. Otherwise seccomp RET_TRAP handlers and kill-action
core dumps lose the original syscall number and fourth argument.
Fixes: 83bd31c2840b ("alpha: enable GENERIC_ENTRY")
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/syscall.h | 4 +++-
arch/alpha/include/asm/thread_info.h | 1 +
arch/alpha/kernel/signal.c | 12 ++++++++++--
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/arch/alpha/include/asm/syscall.h b/arch/alpha/include/asm/syscall.h
index c1394910f584f9ca42367ffc33b1c0ac46cfe112..22315b932f854a71fd3babf6565dda443c6c7a77 100644
--- a/arch/alpha/include/asm/syscall.h
+++ b/arch/alpha/include/asm/syscall.h
@@ -105,14 +105,16 @@ static inline void syscall_set_return_value(struct task_struct *task,
}
}
-/* Restore the original syscall nr after seccomp/ptrace modified regs->r1. */
+/* Preserve the original syscall registers for a skipped syscall. */
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
unsigned long nr = task_thread_info(task)->syscall_saved_nr;
+ regs->r0 = nr;
regs->r1 = nr;
+ task_thread_info(task)->syscall_meta |= ALPHA_SYSCALL_META_ROLLBACK;
}
static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index d781ac79106dd1178b9cb0e094333139db531bed..49bc08f3b5a98fbcb1d4ac919001bf70c3db614b 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -57,6 +57,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
#define ALPHA_SYSCALL_META_SKIP 0x2
#define ALPHA_SYSCALL_META_FORCE_SUCCESS 0x4
+#define ALPHA_SYSCALL_META_ROLLBACK 0x10
/*
* Thread information flags:
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 441d8dd61055d5ddc321c2221984eab8aca5d206..3fae37b4593f22f07a375ab7bc0b0712d0130a07 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -587,10 +587,11 @@ alpha_syscall_enter_select(struct pt_regs *regs, long syscall)
* entry work did not already change the return state.
*/
if (unlikely(!permit || (unsigned long)nr >= NR_syscalls)) {
- if (regs->r0 == saved_r0 && regs->r19 == saved_r19)
+ if (!(ti->syscall_meta & ALPHA_SYSCALL_META_ROLLBACK) &&
+ regs->r0 == saved_r0 && regs->r19 == saved_r19)
syscall_set_return_value(current, regs, -ENOSYS, 0);
- ti->syscall_meta = ALPHA_SYSCALL_META_SKIP;
+ ti->syscall_meta |= ALPHA_SYSCALL_META_SKIP;
return fn; /* ignored by asm when SKIP is set */
}
@@ -617,6 +618,13 @@ alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret)
instrumentation_begin();
+ if (meta & ALPHA_SYSCALL_META_ROLLBACK) {
+ ti->syscall_saved_nr = 0;
+ instrumentation_end();
+ syscall_exit_to_user_mode(regs);
+ return;
+ }
+
if (meta & ALPHA_SYSCALL_META_SKIP) {
/*
* Skip-dispatch path: ptrace/seccomp may already have installed
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 04/14] alpha: fix syscall restart eligibility
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (2 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 03/14] alpha: preserve rolled-back registers for SIGSYS Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 05/14] alpha: distinguish skipped syscalls from invalid numbers Magnus Lindholm
` (9 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
After GENERIC_ENTRY, stale restart state or a successful syscall result
such as 512 can be mistaken for a restart code, corrupting r0 or the PC.
Clear restart eligibility after use and before returning to userspace,
including signal-context restore. Require a3 to indicate an error before
handling restart codes, preserving the saved arguments for replay.
Save the fourth argument before entry work can replace r19 with the
a3 error flag. Preserve that saved value when seccomp or ptrace skips
dispatch and supplies a restart error; dispatched syscalls still save
the argument after any ptrace changes.
Fixes: 83bd31c2840b ("alpha: enable GENERIC_ENTRY")
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/entry-common.h | 10 ++++++++++
arch/alpha/kernel/signal.c | 13 ++++++++++---
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/arch/alpha/include/asm/entry-common.h b/arch/alpha/include/asm/entry-common.h
index a811c73454d28dbc166b83b6f5cd550da339b5fb..85dabd1021da012269eb28acb3ce2da21e0ad706 100644
--- a/arch/alpha/include/asm/entry-common.h
+++ b/arch/alpha/include/asm/entry-common.h
@@ -4,6 +4,7 @@
#include <asm/stacktrace.h> /* For on_thread_stack() */
#include <asm/syscall.h>
+#include <asm/thread_info.h>
#define arch_exit_to_user_mode_work arch_exit_to_user_mode_work
@@ -11,4 +12,13 @@ static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
unsigned long ti_work)
{
}
+
+#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
+static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
+ unsigned long ti_work)
+{
+ /* An interrupt after returning to user mode must not restart a syscall. */
+ current_thread_info()->syscall_saved_nr = 0;
+}
+
#endif
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 3fae37b4593f22f07a375ab7bc0b0712d0130a07..ab32affa09c41152eabd1f3be92a126a85fb7a2d 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -154,6 +154,7 @@ restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
struct switch_stack *sw = (struct switch_stack *)regs - 1;
current->restart_block.fn = do_no_restart_syscall;
+ current_thread_info()->syscall_saved_nr = 0;
current_thread_info()->status |= TS_SAVED_FP | TS_RESTORE_FP;
sw->r26 = (unsigned long) ret_from_sys_call;
@@ -497,17 +498,20 @@ do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
unsigned long single_stepping = ptrace_cancel_bpt(current);
struct ksignal ksig;
+ /* Consume restart state once, even if the exit loop repeats. */
+ current_thread_info()->syscall_saved_nr = 0;
+
/* This lets the debugger run, ... */
if (get_signal(&ksig)) {
/* ... so re-check the single stepping. */
single_stepping |= ptrace_cancel_bpt(current);
/* Whee! Actually deliver the signal. */
- if (r0)
+ if (r0 && regs->r19)
syscall_restart(r0, r19, regs, &ksig.ka);
handle_signal(&ksig, regs);
} else {
single_stepping |= ptrace_cancel_bpt(current);
- if (r0) {
+ if (r0 && regs->r19) {
switch (regs->r0) {
case ERESTARTNOHAND:
case ERESTARTSYS:
@@ -571,6 +575,7 @@ alpha_syscall_enter_select(struct pt_regs *regs, long syscall)
ti->syscall_meta = 0;
ti->syscall_saved_nr = syscall;
+ ti->syscall_saved_r19 = saved_r19;
if (!(ti->status & TS_SAVED_FP)) {
ti->status |= TS_SAVED_FP;
@@ -614,7 +619,9 @@ alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret)
unsigned long meta = ti->syscall_meta;
ti->syscall_meta = 0;
- ti->syscall_saved_r19 = regs->r19;
+ /* Entry work may have replaced argument 4 with the a3 error flag. */
+ if (!(meta & ALPHA_SYSCALL_META_SKIP))
+ ti->syscall_saved_r19 = regs->r19;
instrumentation_begin();
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 05/14] alpha: distinguish skipped syscalls from invalid numbers
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (3 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 04/14] alpha: fix syscall restart eligibility Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 06/14] alpha: dispatch system calls from C Magnus Lindholm
` (8 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
An out-of-range syscall number other than -1 must return ENOSYS even
when a tracer has changed the return registers. Keep explicit results
only when entry work rejects dispatch or the number is the -1 abort
sentinel. The generic-entry conversion incorrectly treats both cases
as skipped calls and preserves tracer results for invalid numbers.
Track explicitly supplied r0 values instead of inferring them from
register contents. Alpha cannot preset its complete ENOSYS return state
before entry work because r19 is still argument 4. Value comparisons
can overwrite legitimate results, including -1, the original syscall
number and a seccomp errno matching the entry registers.
Mark results supplied by syscall_set_return_value(), scalar ptrace
result writes and regset writes covering r0. Keep number-only aborts
returning ENOSYS. After a legacy r0=-1 abort, subsequent r0 writes are
results, not another syscall-number substitution. Honor the supplied
r19 error flag for regsets instead of turning small successes into
errors. Writes outside r0 and empty regset writes must not mark it.
Preserve seccomp return values, SIGSYS rollback and saved restart
arguments. The existing per-syscall metadata reset prevents a supplied
result from carrying over to another syscall.
Fixes: 83bd31c2840b ("alpha: enable GENERIC_ENTRY")
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/syscall.h | 2 +-
arch/alpha/include/asm/thread_info.h | 1 +
arch/alpha/kernel/ptrace.c | 25 +++++++++---------------
arch/alpha/kernel/signal.c | 37 ++++++++----------------------------
4 files changed, 19 insertions(+), 46 deletions(-)
diff --git a/arch/alpha/include/asm/syscall.h b/arch/alpha/include/asm/syscall.h
index 22315b932f854a71fd3babf6565dda443c6c7a77..52fa96ea57caba5f04c2c0c3d9ea31b909eb9f60 100644
--- a/arch/alpha/include/asm/syscall.h
+++ b/arch/alpha/include/asm/syscall.h
@@ -94,7 +94,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
-
+ task_thread_info(task)->syscall_meta |= ALPHA_SYSCALL_META_RESULT;
if (error) {
/* error is negative errno in this tree */
regs->r0 = (unsigned long)(-error); /* positive errno */
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 49bc08f3b5a98fbcb1d4ac919001bf70c3db614b..78f9f60d4ad197c27cd05bfd6a5c20af22bee7a3 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -58,6 +58,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
#define ALPHA_SYSCALL_META_SKIP 0x2
#define ALPHA_SYSCALL_META_FORCE_SUCCESS 0x4
#define ALPHA_SYSCALL_META_ROLLBACK 0x10
+#define ALPHA_SYSCALL_META_RESULT 0x20
/*
* Thread information flags:
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index dba7e9905cfa842dbfe851b3e6ab996c94f7ee46..08e2401cb7e005795a04e169f0c53cf9ed35adb5 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -280,21 +280,6 @@ static void alpha_elf_gregs_set(struct task_struct *child,
if (nwords > 32)
ti->pcb.unique = src[32];
-
-/*
- * PTRACE_SETREGSET can be used at a syscall-entry stop to skip the
- * syscall by setting the syscall number to -1. The seccomp/ptrace
- * selftests use this to synthesize errno returns.
- *
- * Alpha uses r19/a3 as the error flag, so a skipped syscall with a
- * small positive r0 and a clear r19 must be normalized to an error
- * return.
- */
- if (pt->r1 == (unsigned long)-1 &&
- pt->r19 == 0 &&
- pt->r0 > 0 &&
- pt->r0 < MAX_ERRNO)
- pt->r19 = 1;
}
static int
@@ -328,7 +313,8 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
* mutable syscall number in regs->r1.
*/
- if (regno == 0 && regs->r1 == old_r0 &&
+ if (regno == 0 && regs->r1 != (unsigned long)-1 &&
+ regs->r1 == old_r0 &&
(data == (unsigned long)-1 ||
(regs->r19 == 0 && data < NR_syscalls))) {
regs->r1 = data;
@@ -339,6 +325,9 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
*/
if (data == (unsigned long)-1)
regs->r19 = 0;
+ } else if (regno == 0) {
+ /* Once dispatch is cancelled, even -1 is a valid result. */
+ task_thread_info(task)->syscall_meta |= ALPHA_SYSCALL_META_RESULT;
}
return 0;
}
@@ -535,6 +524,7 @@ static int alpha_regset_set(struct task_struct *target,
{
elf_gregset_t gregs;
unsigned int nwords;
+ bool writes_r0 = count && pos < sizeof(elf_greg_t);
if (pos + count > sizeof(gregs))
return -EIO;
@@ -551,6 +541,9 @@ static int alpha_regset_set(struct task_struct *target,
nwords = sizeof(gregs) / sizeof(elf_greg_t);
alpha_elf_gregs_set(target, gregs, nwords);
+ /* Only count r0 bytes actually supplied, not the preserved registers. */
+ if (writes_r0)
+ task_thread_info(target)->syscall_meta |= ALPHA_SYSCALL_META_RESULT;
return 0;
}
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index ab32affa09c41152eabd1f3be92a126a85fb7a2d..f972f690eb678b9201e340624a60fe26ad7f23c8 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -567,7 +567,6 @@ asmlinkage unsigned long
alpha_syscall_enter_select(struct pt_regs *regs, long syscall)
{
struct thread_info *ti = current_thread_info();
- unsigned long saved_r0 = regs->r0;
unsigned long saved_r19 = regs->r19;
unsigned long fn = (unsigned long)sys_ni_syscall;
long nr = syscall;
@@ -584,22 +583,20 @@ alpha_syscall_enter_select(struct pt_regs *regs, long syscall)
permit = syscall_enter_from_user_mode_randomize_stack(regs, &nr);
- /*
- * Alpha cannot preset the full -ENOSYS return state before generic
- * entry handling, because r19 is still syscall argument 4 on the
- * normal dispatch path. So provide the default -ENOSYS result only
- * here, after we know no real syscall will be invoked, and only if
- * entry work did not already change the return state.
- */
- if (unlikely(!permit || (unsigned long)nr >= NR_syscalls)) {
- if (!(ti->syscall_meta & ALPHA_SYSCALL_META_ROLLBACK) &&
- regs->r0 == saved_r0 && regs->r19 == saved_r19)
+ if (unlikely(!permit || nr == -1)) {
+ /* r19 is still argument 4 unless a hook supplied a result. */
+ if (!(ti->syscall_meta & (ALPHA_SYSCALL_META_RESULT |
+ ALPHA_SYSCALL_META_ROLLBACK)))
syscall_set_return_value(current, regs, -ENOSYS, 0);
ti->syscall_meta |= ALPHA_SYSCALL_META_SKIP;
return fn; /* ignored by asm when SKIP is set */
}
+ /* Invalid numbers other than -1 must invoke sys_ni_syscall(). */
+ if (unlikely((unsigned long)nr >= NR_syscalls))
+ return fn;
+
instrumentation_begin();
{
unsigned long index;
@@ -633,24 +630,6 @@ alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret)
}
if (meta & ALPHA_SYSCALL_META_SKIP) {
- /*
- * Skip-dispatch path: ptrace/seccomp may already have installed
- * the return state in r0/r19. Preserve it unless the syscall was
- * skipped with no explicit return value.
- *
- * Generic PTRACE_SET_SYSCALL_INFO changes only the syscall-number
- * shadow, so r1 == -1 while r0 still contains the original Alpha
- * syscall number. Legacy PTRACE_POKEUSR based skipping can leave
- * r0 == -1 with a3/r19 still indicating success. Both represent
- * an unhandled skipped syscall and should become ENOSYS/a3=1.
- */
- if (regs->r1 == (unsigned long)-1 &&
- (regs->r0 == ti->syscall_saved_nr ||
- regs->r0 == (unsigned long)-1)) {
- regs->r0 = ENOSYS;
- regs->r19 = 1;
- }
-
instrumentation_end();
syscall_exit_to_user_mode(regs);
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 06/14] alpha: dispatch system calls from C
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (4 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 05/14] alpha: distinguish skipped syscalls from invalid numbers Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 07/14] alpha: use generic entry helpers for interrupts and exceptions Magnus Lindholm
` (7 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Move syscall dispatch and result encoding into alpha_syscall(), keeping
the complete user switch_stack available throughout the C call. Use the
generic fork/clone handlers and remove the assembly dispatch and sigreturn
wrappers. Preserve Alpha's r0/a3 ABI, ptrace/seccomp overrides and restored
signal contexts.
The syscall table names also enable tracepoints for fork, vfork, clone,
clone3, sigreturn and rt_sigreturn.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/syscall.h | 18 +----
arch/alpha/include/asm/thread_info.h | 1 +
arch/alpha/kernel/Makefile | 2 +-
arch/alpha/kernel/asm-offsets.c | 1 -
arch/alpha/kernel/entry.S | 132 +--------------------------------
arch/alpha/kernel/proto.h | 10 +--
arch/alpha/kernel/signal.c | 126 +++----------------------------
arch/alpha/kernel/syscall.c | 85 +++++++++++++++++++++
arch/alpha/kernel/syscalls/syscall.tbl | 10 +--
9 files changed, 113 insertions(+), 272 deletions(-)
diff --git a/arch/alpha/include/asm/syscall.h b/arch/alpha/include/asm/syscall.h
index 52fa96ea57caba5f04c2c0c3d9ea31b909eb9f60..740ac96cef55d28bcf45251fc722b35421a9f2d5 100644
--- a/arch/alpha/include/asm/syscall.h
+++ b/arch/alpha/include/asm/syscall.h
@@ -29,12 +29,8 @@ static inline long syscall_get_error(struct task_struct *task,
/*
- * Alpha syscall ABI / kernel conventions:
- * - PAL provides syscall number in r0 on entry.
- * - The kernel tracks the active syscall number in regs->r1 (mutable) and
- * preserves the original syscall number in regs->r2 for rollback/restart.
- * - Return value is in regs->r0, with regs->r19 ("a3") as the error flag
- * (0=success, 1=error; on error regs->r0 holds positive errno).
+ * The syscall number arrives in r0. Entry saves the original in thread_info
+ * for rollback and restart, while tracers can change the number in r1.
*/
static inline long syscall_get_nr(struct task_struct *task,
@@ -80,14 +76,8 @@ static inline void syscall_set_arguments(struct task_struct *task,
regs->r21 = args[5];
}
/*
- * Set return value for a syscall.
- * Alpha uses r0 for return value and r19 ("a3") as the error indicator:
- * a3 = 0 => success
- * a3 = 1 => error, and userspace interprets r0 as errno (positive).
- *
- * The kernel reports errors to userspace by setting a3=1 and placing a
- * positive errno value in r0. Some syscall paths do this in entry.S,
- * while others (e.g. seccomp/ptrace helpers) use syscall_set_return_value().
+ * On error, r0 holds a positive errno and a3 is set.
+ * On success, r0 holds the result and a3 is clear.
*/
static inline void syscall_set_return_value(struct task_struct *task,
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 78f9f60d4ad197c27cd05bfd6a5c20af22bee7a3..94bdf9016705cc6b0aea64c3f601de3ef555eb7b 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -57,6 +57,7 @@ register unsigned long *current_stack_pointer __asm__ ("$30");
#define ALPHA_SYSCALL_META_SKIP 0x2
#define ALPHA_SYSCALL_META_FORCE_SUCCESS 0x4
+#define ALPHA_SYSCALL_META_RESTORED 0x8
#define ALPHA_SYSCALL_META_ROLLBACK 0x10
#define ALPHA_SYSCALL_META_RESULT 0x20
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 9d35715bd440518b327ad576b78ad35f61433bab..668556d8496c0c3ee03996cf5a4a0ee56b980891 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -8,7 +8,7 @@ asflags-y := $(KBUILD_CFLAGS)
ccflags-y := -Wno-sign-compare
obj-y := head.o entry.o traps.o process.o osf_sys.o irq.o \
- irq_alpha.o signal.o setup.o ptrace.o time.o \
+ irq_alpha.o signal.o syscall.o setup.o ptrace.o time.o \
systbls.o err_common.o io.o bugs.o termios.o \
stacktrace.o
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
index 22ed3c975b1ceb014806fec5d2afc2140ac3e03a..b575dcf367bfde210fa19bd955f1163877b752d6 100644
--- a/arch/alpha/kernel/asm-offsets.c
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -22,7 +22,6 @@ static void __used foo(void)
DEFINE(SP_OFF, offsetof(struct pt_regs, ps));
DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs));
- DEFINE(TI_SYSCALL_META, offsetof(struct thread_info, syscall_meta));
BLANK();
DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack));
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 790389a15c3ce15d5b8eeae5a67e88443e5430a0..d67ccfc8abac4b97ceb6fa8c7bad8024b9bf5660 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -8,9 +8,6 @@
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/pal.h>
-#include <asm/errno.h>
-#include <asm/unistd.h>
-#include <linux/errno.h>
.text
.set noat
@@ -473,9 +470,6 @@ CFI_END_OSF_FRAME entDbg
.cfi_rel_offset $gp, 16
entSys:
SAVE_ALL
- ldq $1, 0($sp) /* syscall nr from saved r0 */
- stq $1, 8($sp) /* regs->r1 = shadow syscall nr */
-
lda $8, 0x3fff
bic $sp, $8, $8
@@ -483,47 +477,13 @@ entSys:
stq $17, SP_OFF+32($sp)
stq $18, SP_OFF+40($sp)
- mov $0, $1
lda $16, 7
call_pal PAL_swpipl
- mov $1, $0
mov $sp, $16
- mov $0, $17 /* pv = selected syscall function */
-
- DO_SWITCH_STACK
- jsr $26, alpha_syscall_enter_select
- ldgp $gp, 0($26)
- UNDO_SWITCH_STACK
-
- /*
- * C returned syscall function pointer in $0.
- * It also stored SKIP in TI_SYSCALL_META if dispatch is skipped.
- */
- lda $8, 0x3fff
- bic $sp, $8, $8
- ldq $3, TI_SYSCALL_META($8)
- lda $6, ALPHA_SYSCALL_META_SKIP
- and $3, $6, $6
- bne $6, skip_dispatch
-
-
- mov $0, $27
- ldq $16, SP_OFF+24($sp)
- ldq $17, SP_OFF+32($sp)
- ldq $18, SP_OFF+40($sp)
- ldq $19, 72($sp)
- ldq $20, 80($sp)
- ldq $21, 88($sp)
-
- jsr $26, ($27), sys_ni_syscall
- ldgp $gp, 0($26)
-
-skip_dispatch:
- mov $0, $17 /* raw ret; ignored if SKIP is set */
- mov $sp, $16 /* regs */
+ /* Keep the complete user context above all C call frames. */
DO_SWITCH_STACK
- jsr $26, alpha_finish_syscall_to_user_mode
+ jsr $26, alpha_syscall
ldgp $gp, 0($26)
UNDO_SWITCH_STACK
@@ -538,25 +498,6 @@ restore_other:
RESTORE_ALL
call_pal PAL_rti
-ret_to_user_from_syscall:
- lda $8, 0x3fff
- bic $sp, $8, $8
-
- mov $sp, $16
- DO_SWITCH_STACK
- jsr $26, alpha_syscall_exit_to_user_mode
- ldgp $gp, 0($26)
- UNDO_SWITCH_STACK
- br restore_all
-
- .align 4
- .globl ret_from_sys_call
-ret_from_sys_call:
- ldq $0, SP_OFF($sp)
- and $0, 8, $0
- beq $0, ret_to_kernel
- br ret_to_user_from_syscall
-
ret_from_exception:
ldq $0, SP_OFF($sp)
and $0, 8, $0
@@ -720,72 +661,3 @@ ret_from_kernel_thread:
jsr $26, ($9)
br $31, ret_to_user_from_exception
.end ret_from_kernel_thread
-
-\f
-/*
- * Special system calls. Most of these are special in that they either
- * have to play switch_stack games.
- */
-
-.macro fork_like name
- .align 4
- .globl alpha_\name
- .ent alpha_\name
-alpha_\name:
- .prologue 0
- bsr $1, do_switch_stack
- // NB: if anyone adds preemption, this block will need to be protected
- ldl $1, TI_STATUS($8)
- and $1, TS_SAVED_FP, $3
- or $1, TS_SAVED_FP, $2
- bne $3, 1f
- stl $2, TI_STATUS($8)
- bsr $26, __save_fpu
-1:
- jsr $26, sys_\name
- ldq $26, 56($sp)
- lda $sp, SWITCH_STACK_SIZE($sp)
- ret
-.end alpha_\name
-.endm
-
-fork_like fork
-fork_like vfork
-fork_like clone
-fork_like clone3
-
-.macro sigreturn_like name
- .align 4
- .globl sys_\name
- .ent sys_\name
-sys_\name:
- .prologue 0
- mov $sp, $10
- lda $sp, -SWITCH_STACK_SIZE($sp)
- jsr $26, do_\name
-1: br $1, undo_switch_stack
- br ret_from_sys_call
-.end sys_\name
-.endm
-
-sigreturn_like sigreturn
-sigreturn_like rt_sigreturn
-
- .align 4
- .globl alpha_syscall_zero
- .ent alpha_syscall_zero
-alpha_syscall_zero:
- .prologue 0
- /* Special because it needs to do something opposite to
- force_successful_syscall_return(). We use the saved
- syscall number for that, zero meaning "not an error".
- That works nicely, but for real syscall 0 we need to
- make sure that this logics doesn't get confused.
- Store a non-zero there - -ENOSYS we need in register
- for our return value will do just fine.
- */
- lda $0, -ENOSYS
- unop
- stq $0, 0($sp)
- ret
-.end alpha_syscall_zero
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index 7ece3b635e27ca04fb8fa93d9118e8be9a225b66..90af335cd6798ad4039ecc2a3c67505eadbd32a2 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -169,16 +169,12 @@ extern int ptrace_set_bpt (struct task_struct *child);
extern int ptrace_cancel_bpt (struct task_struct *child);
/* signal.c */
-struct sigcontext;
-extern void do_sigreturn(struct sigcontext __user *);
-struct rt_sigframe;
-extern void do_rt_sigreturn(struct rt_sigframe __user *);
extern void alpha_schedule_user_work(void);
extern void do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19);
-extern void alpha_syscall_exit_to_user_mode(struct pt_regs *regs);
extern void alpha_exit_to_user_mode(struct pt_regs *regs);
-extern void alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret);
-extern unsigned long alpha_syscall_enter_select(struct pt_regs *regs, long syscall);
+
+/* syscall.c */
+extern void alpha_syscall(struct pt_regs *regs);
/* traps.c */
extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15);
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index f972f690eb678b9201e340624a60fe26ad7f23c8..c6dd0f2864ade320d59cf1531764640bc6713aa6 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -34,8 +34,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage void ret_from_sys_call(void);
-
/*
* The OSF/1 sigprocmask calling sequence is different from the
* C sigprocmask() sequence..
@@ -157,8 +155,6 @@ restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
current_thread_info()->syscall_saved_nr = 0;
current_thread_info()->status |= TS_SAVED_FP | TS_RESTORE_FP;
- sw->r26 = (unsigned long) ret_from_sys_call;
-
scoped_user_read_access(sc, Efault) {
unsafe_get_user(regs->pc, &sc->sc_pc, Efault);
unsafe_get_user(regs->r0, sc->sc_regs+0, Efault);
@@ -207,12 +203,14 @@ Efault:
a given sigcontext. This because it's impossible to set *all*
registers and transfer control from userland. */
-asmlinkage void
-do_sigreturn(struct sigcontext __user *sc)
+SYSCALL_DEFINE1(sigreturn, struct sigcontext __user *, sc)
{
struct pt_regs *regs = current_pt_regs();
sigset_t set;
+ /* The restored r0/r19 are user state, not a syscall result. */
+ current_thread_info()->syscall_meta |= ALPHA_SYSCALL_META_RESTORED;
+
scoped_user_read_access(sc, give_sigsegv)
unsafe_get_user(set.sig[0], &sc->sc_mask, give_sigsegv);
@@ -226,18 +224,21 @@ do_sigreturn(struct sigcontext __user *sc)
send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *) regs->pc,
current);
}
- return;
+ return 0;
give_sigsegv:
force_sig(SIGSEGV);
+ return 0;
}
-asmlinkage void
-do_rt_sigreturn(struct rt_sigframe __user *frame)
+SYSCALL_DEFINE1(rt_sigreturn, struct rt_sigframe __user *, frame)
{
struct pt_regs *regs = current_pt_regs();
sigset_t set;
+ /* The restored r0/r19 are user state, not a syscall result. */
+ current_thread_info()->syscall_meta |= ALPHA_SYSCALL_META_RESTORED;
+
/* Verify that it's a good ucontext_t before using it */
if (!access_ok(&frame->uc, sizeof(frame->uc)))
goto give_sigsegv;
@@ -254,10 +255,11 @@ do_rt_sigreturn(struct rt_sigframe __user *frame)
send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *) regs->pc,
current);
}
- return;
+ return 0;
give_sigsegv:
force_sig(SIGSEGV);
+ return 0;
}
@@ -543,16 +545,6 @@ asmlinkage void alpha_exit_to_user_mode(struct pt_regs *regs)
exit_to_user_mode();
}
-/*
- * Syscall return reaches here after Alpha-specific r0/a3 result encoding.
- * Delegate syscall-exit work and final exit-to-user handling to generic
- * entry code; low-level PAL restore remains in assembly.
- */
-asmlinkage void alpha_syscall_exit_to_user_mode(struct pt_regs *regs)
-{
- syscall_exit_to_user_mode(regs);
-}
-
void arch_do_signal_or_restart(struct pt_regs *regs)
{
struct thread_info *ti = current_thread_info();
@@ -562,97 +554,3 @@ void arch_do_signal_or_restart(struct pt_regs *regs)
preempt_enable();
do_signal(regs, ti->syscall_saved_nr, ti->syscall_saved_r19);
}
-
-asmlinkage unsigned long
-alpha_syscall_enter_select(struct pt_regs *regs, long syscall)
-{
- struct thread_info *ti = current_thread_info();
- unsigned long saved_r19 = regs->r19;
- unsigned long fn = (unsigned long)sys_ni_syscall;
- long nr = syscall;
- bool permit;
-
- ti->syscall_meta = 0;
- ti->syscall_saved_nr = syscall;
- ti->syscall_saved_r19 = saved_r19;
-
- if (!(ti->status & TS_SAVED_FP)) {
- ti->status |= TS_SAVED_FP;
- __save_fpu();
- }
-
- permit = syscall_enter_from_user_mode_randomize_stack(regs, &nr);
-
- if (unlikely(!permit || nr == -1)) {
- /* r19 is still argument 4 unless a hook supplied a result. */
- if (!(ti->syscall_meta & (ALPHA_SYSCALL_META_RESULT |
- ALPHA_SYSCALL_META_ROLLBACK)))
- syscall_set_return_value(current, regs, -ENOSYS, 0);
-
- ti->syscall_meta |= ALPHA_SYSCALL_META_SKIP;
- return fn; /* ignored by asm when SKIP is set */
- }
-
- /* Invalid numbers other than -1 must invoke sys_ni_syscall(). */
- if (unlikely((unsigned long)nr >= NR_syscalls))
- return fn;
-
- instrumentation_begin();
- {
- unsigned long index;
-
- index = array_index_nospec((unsigned long)nr, NR_syscalls);
- fn = (unsigned long)sys_call_table[index];
- }
- instrumentation_end();
-
- return fn;
-}
-
-asmlinkage noinstr void
-alpha_finish_syscall_to_user_mode(struct pt_regs *regs, long ret)
-{
- struct thread_info *ti = current_thread_info();
- unsigned long meta = ti->syscall_meta;
-
- ti->syscall_meta = 0;
- /* Entry work may have replaced argument 4 with the a3 error flag. */
- if (!(meta & ALPHA_SYSCALL_META_SKIP))
- ti->syscall_saved_r19 = regs->r19;
-
- instrumentation_begin();
-
- if (meta & ALPHA_SYSCALL_META_ROLLBACK) {
- ti->syscall_saved_nr = 0;
- instrumentation_end();
- syscall_exit_to_user_mode(regs);
- return;
- }
-
- if (meta & ALPHA_SYSCALL_META_SKIP) {
- instrumentation_end();
-
- syscall_exit_to_user_mode(regs);
- return;
- }
-
- /*
- * Some successful syscalls, notably legacy ptrace PEEK requests,
- * return arbitrary data in r0. That data may have the bit pattern
- * of a negative errno, so do not infer failure from ret < 0 when
- * arch code explicitly requested a successful Alpha return.
- */
- if (meta & ALPHA_SYSCALL_META_FORCE_SUCCESS) {
- regs->r0 = ret;
- regs->r19 = 0;
- } else if (ret < 0) {
- regs->r0 = -ret;
- regs->r19 = 1;
- } else {
- regs->r0 = ret;
- regs->r19 = 0;
- }
-
- instrumentation_end();
- syscall_exit_to_user_mode(regs);
-}
diff --git a/arch/alpha/kernel/syscall.c b/arch/alpha/kernel/syscall.c
new file mode 100644
index 0000000000000000000000000000000000000000..652406905a249af743109e369cace97d39f676c9
--- /dev/null
+++ b/arch/alpha/kernel/syscall.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Alpha syscall entry and result encoding. */
+#include <linux/entry-common.h>
+#include <linux/nospec.h>
+#include <linux/syscalls.h>
+
+#include <asm/syscall.h>
+
+#include "proto.h"
+
+typedef long (*syscall_fn_t)(unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+
+static void alpha_set_syscall_result(struct pt_regs *regs, long ret)
+{
+ struct thread_info *ti = current_thread_info();
+ unsigned long meta = ti->syscall_meta;
+
+ ti->syscall_meta = 0;
+ if (meta & (ALPHA_SYSCALL_META_RESTORED | ALPHA_SYSCALL_META_ROLLBACK)) {
+ ti->syscall_saved_nr = 0;
+ ti->syscall_saved_r19 = 0;
+ return;
+ }
+
+ /* Entry work may have replaced argument 4 with the a3 error flag. */
+ if (!(meta & ALPHA_SYSCALL_META_SKIP))
+ ti->syscall_saved_r19 = regs->r19;
+
+ if (meta & ALPHA_SYSCALL_META_SKIP)
+ return;
+
+ /* A successful ptrace PEEK can return data that looks like an errno. */
+ if (meta & ALPHA_SYSCALL_META_FORCE_SUCCESS) {
+ regs->r0 = ret;
+ regs->r19 = 0;
+ } else if (ret < 0) {
+ regs->r0 = -ret;
+ regs->r19 = 1;
+ } else {
+ regs->r0 = ret;
+ regs->r19 = 0;
+ }
+}
+
+/* Called with interrupts disabled and a complete user switch_stack. */
+asmlinkage noinstr void alpha_syscall(struct pt_regs *regs)
+{
+ struct thread_info *ti = current_thread_info();
+ unsigned long saved_r19 = regs->r19;
+ long nr = regs->r0;
+ long ret = -ENOSYS;
+ bool permit;
+
+ regs->r1 = nr;
+ ti->syscall_meta = 0;
+ ti->syscall_saved_nr = nr;
+ ti->syscall_saved_r19 = saved_r19;
+
+ if (!(ti->status & TS_SAVED_FP)) {
+ ti->status |= TS_SAVED_FP;
+ __save_fpu();
+ }
+
+ permit = syscall_enter_from_user_mode_randomize_stack(regs, &nr);
+
+ instrumentation_begin();
+ if (unlikely(!permit || nr == -1)) {
+ /* r19 is still argument 4 unless a hook supplied a result. */
+ if (!(ti->syscall_meta & (ALPHA_SYSCALL_META_RESULT |
+ ALPHA_SYSCALL_META_ROLLBACK)))
+ syscall_set_return_value(current, regs, -ENOSYS, 0);
+ ti->syscall_meta |= ALPHA_SYSCALL_META_SKIP;
+ } else if (likely((unsigned long)nr < NR_syscalls)) {
+ syscall_fn_t syscall_fn;
+
+ syscall_fn = sys_call_table[array_index_nospec(nr, NR_syscalls)];
+ ret = syscall_fn(regs->r16, regs->r17, regs->r18,
+ regs->r19, regs->r20, regs->r21);
+ }
+ alpha_set_syscall_result(regs, ret);
+ instrumentation_end();
+
+ syscall_exit_to_user_mode(regs);
+}
diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl
index 52e3538cc7df415f0b1613eb3db7de56d5bf20a2..f804988f90d6672e3bf409258a0fccc4ba214927 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -7,9 +7,9 @@
#
# The <abi> is always "common" for this file
#
-0 common osf_syscall alpha_syscall_zero
+0 common osf_syscall sys_ni_syscall
1 common exit sys_exit
-2 common fork alpha_fork
+2 common fork sys_fork
3 common read sys_read
4 common write sys_write
5 common osf_old_open sys_ni_syscall
@@ -72,7 +72,7 @@
63 common getpgrp sys_getpgrp
64 common getpagesize sys_getpagesize
65 common osf_mremap sys_ni_syscall
-66 common vfork alpha_vfork
+66 common vfork sys_vfork
67 common stat sys_newstat
68 common lstat sys_newlstat
69 common osf_sbrk sys_ni_syscall
@@ -242,7 +242,7 @@
309 common get_kernel_syms sys_ni_syscall
310 common syslog sys_syslog
311 common reboot sys_reboot
-312 common clone alpha_clone
+312 common clone sys_clone
313 common uselib sys_uselib
314 common mlock sys_mlock
315 common munlock sys_munlock
@@ -474,7 +474,7 @@
542 common fsmount sys_fsmount
543 common fspick sys_fspick
544 common pidfd_open sys_pidfd_open
-545 common clone3 alpha_clone3
+545 common clone3 sys_clone3
546 common close_range sys_close_range
547 common openat2 sys_openat2
548 common pidfd_getfd sys_pidfd_getfd
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 07/14] alpha: use generic entry helpers for interrupts and exceptions
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (5 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 06/14] alpha: dispatch system calls from C Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 08/14] alpha: use generic syscall exit for new tasks Magnus Lindholm
` (6 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Use irqentry_enter()/irqentry_exit() for ordinary interrupts and
exceptions and centralize hardirq accounting in do_entInt(). Keep the
saved switch_stack available for signals and fault fixups; register
restoration and PAL_rti remain in assembly.
Interrupts now save a switch_stack too; generic exit handles kernel IRQ
state restoration. Keep kernel FEN recovery outside entry bookkeeping,
since it can interrupt FP saves and restores during entry or exit.
The special kernel unaligned-access path is unchanged.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/entry-common.h | 7 --
arch/alpha/kernel/entry.S | 138 ++++++----------------------------
arch/alpha/kernel/irq.c | 8 +-
arch/alpha/kernel/irq_alpha.c | 41 +++-------
arch/alpha/kernel/process.c | 2 +-
arch/alpha/kernel/signal.c | 7 +-
arch/alpha/kernel/traps.c | 118 +++++++++++++++++++++++------
arch/alpha/mm/fault.c | 25 +++++-
8 files changed, 154 insertions(+), 192 deletions(-)
diff --git a/arch/alpha/include/asm/entry-common.h b/arch/alpha/include/asm/entry-common.h
index 85dabd1021da012269eb28acb3ce2da21e0ad706..1d3b3d67235858419a069b7d9e4ce44f2e4e5525 100644
--- a/arch/alpha/include/asm/entry-common.h
+++ b/arch/alpha/include/asm/entry-common.h
@@ -6,13 +6,6 @@
#include <asm/syscall.h>
#include <asm/thread_info.h>
-#define arch_exit_to_user_mode_work arch_exit_to_user_mode_work
-
-static __always_inline void arch_exit_to_user_mode_work(struct pt_regs *regs,
- unsigned long ti_work)
-{
-}
-
#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare
static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
unsigned long ti_work)
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index d67ccfc8abac4b97ceb6fa8c7bad8024b9bf5660..2233eb6da7065e7d85cbc668a09e565bcfd75a52 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -185,77 +185,25 @@
* Non-syscall kernel entry points.
*/
-CFI_START_OSF_FRAME entInt
+/* Keep the switch_stack available to generic exit work and fault fixups. */
+.macro EXCEPTION_ENTRY name, handler, regs_arg
+CFI_START_OSF_FRAME \name
SAVE_ALL
- lda $8, 0x3fff
- lda $26, ret_from_exception
- bic $sp, $8, $8
- mov $sp, $19
- jsr $31, do_entInt
-CFI_END_OSF_FRAME entInt
-
-CFI_START_OSF_FRAME entArith
- SAVE_ALL
- lda $8, 0x3fff
- lda $26, ret_from_exception
- bic $sp, $8, $8
- mov $sp, $18
- jsr $31, do_entArith
-CFI_END_OSF_FRAME entArith
-
-CFI_START_OSF_FRAME entMM
- SAVE_ALL
-/* save $9 - $15 so the inline exception code can manipulate them. */
- subq $sp, 64, $sp
- .cfi_adjust_cfa_offset 64
- stq $9, 0($sp)
- stq $10, 8($sp)
- stq $11, 16($sp)
- stq $12, 24($sp)
- stq $13, 32($sp)
- stq $14, 40($sp)
- stq $15, 48($sp)
- .cfi_rel_offset $9, 0
- .cfi_rel_offset $10, 8
- .cfi_rel_offset $11, 16
- .cfi_rel_offset $12, 24
- .cfi_rel_offset $13, 32
- .cfi_rel_offset $14, 40
- .cfi_rel_offset $15, 48
- addq $sp, 64, $19
-/* handle the fault */
+ mov $sp, \regs_arg
+ DO_SWITCH_STACK
lda $8, 0x3fff
bic $sp, $8, $8
- jsr $26, do_page_fault
-/* reload the registers after the exception code played. */
- ldq $9, 0($sp)
- ldq $10, 8($sp)
- ldq $11, 16($sp)
- ldq $12, 24($sp)
- ldq $13, 32($sp)
- ldq $14, 40($sp)
- ldq $15, 48($sp)
- addq $sp, 64, $sp
- .cfi_restore $9
- .cfi_restore $10
- .cfi_restore $11
- .cfi_restore $12
- .cfi_restore $13
- .cfi_restore $14
- .cfi_restore $15
- .cfi_adjust_cfa_offset -64
-/* finish up the syscall as normal. */
+ jsr $26, \handler
+ ldgp $gp, 0($26)
+ UNDO_SWITCH_STACK
br ret_from_exception
-CFI_END_OSF_FRAME entMM
+CFI_END_OSF_FRAME \name
+.endm
-CFI_START_OSF_FRAME entIF
- SAVE_ALL
- lda $8, 0x3fff
- lda $26, ret_from_exception
- bic $sp, $8, $8
- mov $sp, $17
- jsr $31, do_entIF
-CFI_END_OSF_FRAME entIF
+EXCEPTION_ENTRY entInt, do_entInt, $19
+EXCEPTION_ENTRY entArith, do_entArith, $18
+EXCEPTION_ENTRY entMM, do_page_fault, $19
+EXCEPTION_ENTRY entIF, do_entIF, $17
CFI_START_OSF_FRAME entUna
lda $sp, -256($sp)
@@ -391,53 +339,17 @@ entUnaUser:
.cfi_restore $0
.cfi_adjust_cfa_offset -256
SAVE_ALL /* setup normal kernel stack */
- lda $sp, -64($sp)
- .cfi_adjust_cfa_offset 64
- stq $9, 0($sp)
- stq $10, 8($sp)
- stq $11, 16($sp)
- stq $12, 24($sp)
- stq $13, 32($sp)
- stq $14, 40($sp)
- stq $15, 48($sp)
- .cfi_rel_offset $9, 0
- .cfi_rel_offset $10, 8
- .cfi_rel_offset $11, 16
- .cfi_rel_offset $12, 24
- .cfi_rel_offset $13, 32
- .cfi_rel_offset $14, 40
- .cfi_rel_offset $15, 48
+ mov $sp, $19
+ DO_SWITCH_STACK
lda $8, 0x3fff
- addq $sp, 64, $19
bic $sp, $8, $8
jsr $26, do_entUnaUser
- ldq $9, 0($sp)
- ldq $10, 8($sp)
- ldq $11, 16($sp)
- ldq $12, 24($sp)
- ldq $13, 32($sp)
- ldq $14, 40($sp)
- ldq $15, 48($sp)
- lda $sp, 64($sp)
- .cfi_restore $9
- .cfi_restore $10
- .cfi_restore $11
- .cfi_restore $12
- .cfi_restore $13
- .cfi_restore $14
- .cfi_restore $15
- .cfi_adjust_cfa_offset -64
+ ldgp $gp, 0($26)
+ UNDO_SWITCH_STACK
br ret_from_exception
CFI_END_OSF_FRAME entUna
-CFI_START_OSF_FRAME entDbg
- SAVE_ALL
- lda $8, 0x3fff
- lda $26, ret_from_exception
- bic $sp, $8, $8
- mov $sp, $16
- jsr $31, do_entDbg
-CFI_END_OSF_FRAME entDbg
+EXCEPTION_ENTRY entDbg, do_entDbg, $16
/*
@@ -499,10 +411,11 @@ restore_other:
call_pal PAL_rti
ret_from_exception:
+ .cfi_restore_state
ldq $0, SP_OFF($sp)
and $0, 8, $0
- beq $0, ret_to_kernel
- br ret_to_user_from_exception
+ beq $0, restore_other
+ br restore_all
ret_to_user_from_exception:
@@ -513,13 +426,6 @@ ret_to_user_from_exception:
UNDO_SWITCH_STACK
br restore_all
-ret_to_kernel:
- .cfi_restore_state
- lda $16, 7
- call_pal PAL_swpipl
- LOCKDEP_HARDIRQS_ON_RESTORE SP_OFF($sp)
- br restore_other
-
CFI_END_OSF_FRAME entSys
/*
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 5867a165504511a6e693bc6a200e7e9a69415103..c7dfa895c64832a4669a44d0bf92e99d0c5247ee 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -86,9 +86,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
}
/*
- * handle_irq handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
+ * Device IRQs use this path. do_entInt() handles hardirq accounting.
*/
#define MAX_ILLEGAL_IRQS 16
@@ -109,8 +107,6 @@ handle_irq(int irq)
static unsigned int illegal_count=0;
struct irq_desc *desc;
- irq_enter();
-
desc = irq_to_desc(irq);
if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
illegal_count < MAX_ILLEGAL_IRQS)) {
@@ -118,10 +114,8 @@ handle_irq(int irq)
illegal_count++;
printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
irq);
- irq_exit();
return;
}
generic_handle_irq_desc(desc);
- irq_exit();
}
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 8366d6de439d1cd26fd0cadb3fb26f93a7cee8a1..270d98116ffef4ea9c314222fe64c8e3b19628e5 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -4,6 +4,7 @@
*/
#include <linux/init.h>
+#include <linux/irq-entry-common.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
@@ -41,38 +42,25 @@ EXPORT_SYMBOL(perf_irq);
* The main interrupt entry point.
*/
-asmlinkage void
+asmlinkage noinstr void
do_entInt(unsigned long type, unsigned long vector,
unsigned long la_ptr, struct pt_regs *regs)
{
+ irqentry_state_t state;
struct pt_regs *old_regs;
- /*
- * Disable interrupts during IRQ handling.
- * Note that there is no matching local_irq_enable() due to
- * severe problems with RTI at IPL0 and some MILO PALcode
- * (namely LX164).
- *
- * PALcode has already raised PS.IPL to the level of the interrupt
- * being delivered. For an IPL 7 entry - a machine check or a system
- * event - that is IPL_MAX, which is what arch_irqs_disabled() tests
- * for, so local_irq_disable() would decide interrupts were already
- * off and skip trace_hardirqs_off(). lockdep would then spend the
- * whole handler believing interrupts are enabled. Drive the
- * annotation from lockdep's own state rather than the hardware IPL.
- */
+ /* PALcode raises IPL only to the level of the delivered interrupt. */
raw_local_irq_disable();
- if (lockdep_hardirqs_enabled())
- trace_hardirqs_off();
+ state = irqentry_enter(regs);
+ instrumentation_begin();
+ irq_enter_rcu();
old_regs = set_irq_regs(regs);
switch (type) {
case 0:
#ifdef CONFIG_SMP
- irq_enter();
handle_ipi(regs);
- irq_exit();
break;
#else
irq_err_count++;
@@ -80,23 +68,16 @@ do_entInt(unsigned long type, unsigned long vector,
break;
#endif
case 1:
- /* handle_irq() already does irq_enter()/irq_exit() */
handle_irq(RTC_IRQ);
break;
case 2:
- irq_enter();
alpha_mv.machine_check(vector, la_ptr);
- irq_exit();
break;
case 3:
- irq_enter();
alpha_mv.device_interrupt(vector);
- irq_exit();
break;
case 4:
- irq_enter();
perf_irq(la_ptr, regs);
- irq_exit();
break;
default:
pr_crit("Hardware intr %lu %lx? Huh?\n", type, vector);
@@ -105,11 +86,11 @@ do_entInt(unsigned long type, unsigned long vector,
}
set_irq_regs(old_regs);
+ irq_exit_rcu();
+ instrumentation_end();
- /*
- * Intentionally no local_irq_enable(): Alpha historically avoids
- * enabling at IPL0 here due to PAL/RTI issues (LX164/MILO note).
- */
+ /* Do not lower IPL here before PAL_rti (LX164/MILO PALcode). */
+ irqentry_exit(regs, state);
}
void notrace lockdep_on_restore(unsigned long ps,
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 7861c9e767b720a5939553e9ff3218519ee8e4b5..2182496c535661f399a73400e308c0a7fc6d76f1 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -136,7 +136,7 @@ common_shutdown_1(void *generic_ptr)
/* If we've gotten here after SysRq-b, leave interrupt
context before taking over the console. */
if (in_hardirq())
- irq_exit();
+ irq_exit_rcu();
/* This has the effect of resetting the VGA video origin. */
console_lock();
do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index c6dd0f2864ade320d59cf1531764640bc6713aa6..244fec20294b81e0c749a07321f917befb62b1a7 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -538,11 +538,12 @@ do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
ptrace_set_bpt(current); /* re-set breakpoint */
}
-asmlinkage void alpha_exit_to_user_mode(struct pt_regs *regs)
+asmlinkage noinstr void alpha_exit_to_user_mode(struct pt_regs *regs)
{
+ instrumentation_begin();
local_irq_disable();
- irqentry_exit_to_user_mode_prepare(regs);
- exit_to_user_mode();
+ instrumentation_end();
+ irqentry_exit_to_user_mode(regs);
}
void arch_do_signal_or_restart(struct pt_regs *regs)
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index db6277b3bed03b6d7fd97f483eaa6873d351bbe0..a4209bca38063882a5bebe8dd3a285fd2b39e218 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -10,6 +10,7 @@
*/
#include <linux/cpu.h>
+#include <linux/irq-entry-common.h>
#include <linux/jiffies.h>
#include <linux/mm.h>
#include <linux/sched/signal.h>
@@ -174,9 +175,9 @@ long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);
long alpha_fp_emul (unsigned long pc, unsigned long summary);
#endif
-asmlinkage void
-do_entArith(unsigned long summary, unsigned long write_mask,
- struct pt_regs *regs)
+static void
+handle_entArith(unsigned long summary, unsigned long write_mask,
+ struct pt_regs *regs)
{
long si_code = FPE_FLTINV;
@@ -196,25 +197,29 @@ do_entArith(unsigned long summary, unsigned long write_mask,
send_sig_fault_trapno(SIGFPE, si_code, (void __user *) regs->pc, 0, current);
}
-asmlinkage void
-do_entIF(unsigned long type, struct pt_regs *regs)
+asmlinkage noinstr void
+do_entArith(unsigned long summary, unsigned long write_mask,
+ struct pt_regs *regs)
{
- int signo, code;
+ irqentry_state_t state;
- if (type == 3) { /* FEN fault */
- /* Irritating users can call PAL_clrfen to disable the
- FPU for the process. The kernel will then trap in
- do_switch_stack and undo_switch_stack when we try
- to save and restore the FP registers.
+ raw_local_irq_disable();
+ state = irqentry_enter(regs);
+
+ instrumentation_begin();
+ local_irq_restore(regs->ps);
+ handle_entArith(summary, write_mask, regs);
+ local_irq_disable();
+ instrumentation_end();
+
+ irqentry_exit(regs, state);
+}
+
+static void
+handle_entIF(unsigned long type, struct pt_regs *regs)
+{
+ int signo, code;
- Given that GCC by default generates code that uses the
- FP registers, PAL_clrfen is not useful except for DoS
- attacks. So turn the bleeding FPU back on and be done
- with it. */
- current_thread_info()->pcb.flags |= 1;
- __reload_thread(¤t_thread_info()->pcb);
- return;
- }
if (!user_mode(regs)) {
if (type == 1) {
const unsigned int *data
@@ -330,6 +335,34 @@ do_entIF(unsigned long type, struct pt_regs *regs)
send_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)regs->pc, current);
}
+asmlinkage noinstr void
+do_entIF(unsigned long type, struct pt_regs *regs)
+{
+ irqentry_state_t state;
+
+ raw_local_irq_disable();
+ if (type == 3) {
+ /*
+ * Kernel FEN faults can interrupt entry or exit while saving user FP
+ * state or restoring it. Re-enable the FPU without running entry hooks.
+ */
+ current_thread_info()->pcb.flags |= 1;
+ __reload_thread(¤t_thread_info()->pcb);
+ if (!user_mode(regs))
+ return;
+ }
+ state = irqentry_enter(regs);
+
+ instrumentation_begin();
+ local_irq_restore(regs->ps);
+ if (type != 3)
+ handle_entIF(type, regs);
+ local_irq_disable();
+ instrumentation_end();
+
+ irqentry_exit(regs, state);
+}
+
/* There is an ifdef in the PALcode in MILO that enables a
"kernel debugging entry point" as an unprivileged call_pal.
@@ -337,14 +370,31 @@ do_entIF(unsigned long type, struct pt_regs *regs)
several versions of MILO included in distributions have it enabled,
and if we don't put something on the entry point we'll oops. */
-asmlinkage void
-do_entDbg(struct pt_regs *regs)
+static void
+handle_entDbg(struct pt_regs *regs)
{
die_if_kernel("Instruction fault", regs, 0, NULL);
force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)regs->pc);
}
+asmlinkage noinstr void
+do_entDbg(struct pt_regs *regs)
+{
+ irqentry_state_t state;
+
+ raw_local_irq_disable();
+ state = irqentry_enter(regs);
+
+ instrumentation_begin();
+ local_irq_restore(regs->ps);
+ handle_entDbg(regs);
+ local_irq_disable();
+ instrumentation_end();
+
+ irqentry_exit(regs, state);
+}
+
/*
* entUna has a different register layout to be reasonably simple. It
@@ -649,7 +699,7 @@ s_reg_to_mem (unsigned long s_reg)
static int unauser_reg_offsets[32] = {
R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),
/* r9 ... r15 are stored in front of regs. */
- -64, -56, -48, -40, -32, -24, -16, /* padding at -8 */
+ -64, -56, -48, -40, -32, -24, -16, /* r26 at -8 */
R(r16), R(r17), R(r18),
R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),
R(r27), R(r28), R(gp),
@@ -658,9 +708,9 @@ static int unauser_reg_offsets[32] = {
#undef R
-asmlinkage void
-do_entUnaUser(void __user * va, unsigned long opcode,
- unsigned long reg, struct pt_regs *regs)
+static void
+handle_entUnaUser(void __user *va, unsigned long opcode,
+ unsigned long reg, struct pt_regs *regs)
{
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
@@ -913,6 +963,24 @@ give_sigbus:
return;
}
+asmlinkage noinstr void
+do_entUnaUser(void __user *va, unsigned long opcode,
+ unsigned long reg, struct pt_regs *regs)
+{
+ irqentry_state_t state;
+
+ raw_local_irq_disable();
+ state = irqentry_enter(regs);
+
+ instrumentation_begin();
+ local_irq_restore(regs->ps);
+ handle_entUnaUser(va, opcode, reg, regs);
+ local_irq_disable();
+ instrumentation_end();
+
+ irqentry_exit(regs, state);
+}
+
void
trap_init(void)
{
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index f09f69894cfd65d814ab1cf498c946043fb9e8a3..a46553b5e7d91f6209e2323e92d086989676262c 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -5,6 +5,7 @@
* Copyright (C) 1995 Linus Torvalds
*/
+#include <linux/irq-entry-common.h>
#include <linux/sched/signal.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -130,9 +131,9 @@ static bool is_prefetch(struct pt_regs *regs)
(1ul << (insn >> 26) & 0x30f00001400ul);
}
-asmlinkage void
-do_page_fault(unsigned long address, unsigned long mmcsr,
- long cause, struct pt_regs *regs)
+static void
+handle_page_fault(unsigned long address, unsigned long mmcsr,
+ long cause, struct pt_regs *regs)
{
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
@@ -309,3 +310,21 @@ retry:
}
#endif
}
+
+asmlinkage noinstr void
+do_page_fault(unsigned long address, unsigned long mmcsr,
+ long cause, struct pt_regs *regs)
+{
+ irqentry_state_t state;
+
+ raw_local_irq_disable();
+ state = irqentry_enter(regs);
+
+ instrumentation_begin();
+ local_irq_restore(regs->ps);
+ handle_page_fault(address, mmcsr, cause, regs);
+ local_irq_disable();
+ instrumentation_end();
+
+ irqentry_exit(regs, state);
+}
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 08/14] alpha: use generic syscall exit for new tasks
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (6 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 07/14] alpha: use generic entry helpers for interrupts and exceptions Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 09/14] alpha: remove obsolete core dump register hooks Magnus Lindholm
` (5 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Move fork and kernel-thread startup into C and use
syscall_exit_to_user_mode() for the return to userspace, retaining the
saved user context for exit work.
This also supplies the child syscall-exit tracepoint for fork, vfork,
clone and clone3.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/kernel/entry.S | 23 ++++++++++-------------
arch/alpha/kernel/process.c | 16 ++++++++++++++++
arch/alpha/kernel/proto.h | 6 ++++--
arch/alpha/kernel/signal.c | 8 --------
4 files changed, 30 insertions(+), 23 deletions(-)
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 2233eb6da7065e7d85cbc668a09e565bcfd75a52..5da8c0d17a1d893f59bee1a12f5782276432674d 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -417,11 +417,11 @@ ret_from_exception:
beq $0, restore_other
br restore_all
-ret_to_user_from_exception:
-
- mov $sp, $16
+ret_from_fork_common:
+ mov $17, $16
+ mov $sp, $17
DO_SWITCH_STACK
- jsr $26, alpha_exit_to_user_mode
+ jsr $26, alpha_ret_from_fork
ldgp $gp, 0($26)
UNDO_SWITCH_STACK
br restore_all
@@ -548,9 +548,9 @@ alpha_switch_to:
.align 4
.ent ret_from_fork
ret_from_fork:
- lda $26, ret_to_user_from_exception
- mov $17, $16
- jmp $31, schedule_tail
+ mov $31, $18
+ mov $31, $19
+ br $31, ret_from_fork_common
.end ret_from_fork
/*
@@ -560,10 +560,7 @@ ret_from_fork:
.globl ret_from_kernel_thread
.ent ret_from_kernel_thread
ret_from_kernel_thread:
- mov $17, $16
- jsr $26, schedule_tail
- mov $9, $27
- mov $10, $16
- jsr $26, ($9)
- br $31, ret_to_user_from_exception
+ mov $9, $18
+ mov $10, $19
+ br $31, ret_from_fork_common
.end ret_from_kernel_thread
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 2182496c535661f399a73400e308c0a7fc6d76f1..c7e6e7b593af10305414ea30f5b944b9d21dd2e2 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -10,6 +10,7 @@
*/
#include <linux/cpu.h>
+#include <linux/entry-common.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -226,6 +227,21 @@ flush_thread(void)
current_thread_info()->pcb.unique = 0;
}
+/* The assembly stub keeps the complete user switch_stack below regs. */
+asmlinkage noinstr void alpha_ret_from_fork(struct task_struct *prev,
+ struct pt_regs *regs,
+ int (*fn)(void *), void *fn_arg)
+{
+ instrumentation_begin();
+ schedule_tail(prev);
+ if (fn)
+ fn(fn_arg);
+ instrumentation_end();
+
+ /* A kernel thread may return after a successful kernel_execve(). */
+ syscall_exit_to_user_mode(regs);
+}
+
/*
* Copy architecture-specific thread state
*/
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index 90af335cd6798ad4039ecc2a3c67505eadbd32a2..c418333d0b89d910ec59d1d57d6bcc0550efc4aa 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -164,14 +164,16 @@ extern void entDbg(void);
/* pci.c */
extern void pcibios_claim_one_bus(struct pci_bus *);
+/* process.c */
+extern void alpha_ret_from_fork(struct task_struct *prev, struct pt_regs *regs,
+ int (*fn)(void *), void *fn_arg);
+
/* ptrace.c */
extern int ptrace_set_bpt (struct task_struct *child);
extern int ptrace_cancel_bpt (struct task_struct *child);
/* signal.c */
-extern void alpha_schedule_user_work(void);
extern void do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19);
-extern void alpha_exit_to_user_mode(struct pt_regs *regs);
/* syscall.c */
extern void alpha_syscall(struct pt_regs *regs);
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 244fec20294b81e0c749a07321f917befb62b1a7..e3cb1b50c83d9680032731799b644118b46803bc 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -538,14 +538,6 @@ do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
ptrace_set_bpt(current); /* re-set breakpoint */
}
-asmlinkage noinstr void alpha_exit_to_user_mode(struct pt_regs *regs)
-{
- instrumentation_begin();
- local_irq_disable();
- instrumentation_end();
- irqentry_exit_to_user_mode(regs);
-}
-
void arch_do_signal_or_restart(struct pt_regs *regs)
{
struct thread_info *ti = current_thread_info();
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 09/14] alpha: remove obsolete core dump register hooks
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (7 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 08/14] alpha: use generic syscall exit for new tasks Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 10/14] alpha: use generic syscall audit classification Magnus Lindholm
` (4 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Alpha uses CORE_DUMP_USE_REGSET, so remove the unused per-task ELF
register-copy hooks. Write saved FP registers directly with membuf_write()
instead of copying them through a temporary array. Register layouts and
regset writes are unchanged.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/include/asm/elf.h | 7 -------
arch/alpha/kernel/process.c | 14 --------------
arch/alpha/kernel/ptrace.c | 17 +++--------------
3 files changed, 3 insertions(+), 35 deletions(-)
diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index b15946621d573f630e253b4046fb3ac6e8bbb66b..7a64d4c3e3574aafcec2d23a843f3cdfc6fca780 100644
--- a/arch/alpha/include/asm/elf.h
+++ b/arch/alpha/include/asm/elf.h
@@ -109,18 +109,11 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
struct pt_regs;
struct thread_info;
-struct task_struct;
extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt,
struct thread_info *ti);
#define ELF_CORE_COPY_REGS(DEST, REGS) \
dump_elf_thread(DEST, REGS, current_thread_info());
-/* Similar, but for a thread other than current. */
-
-extern int dump_elf_task(elf_greg_t *dest, struct task_struct *task);
-#define ELF_CORE_COPY_TASK_REGS(TASK, DEST) \
- dump_elf_task(*(DEST), TASK)
-
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This is trivial on Alpha,
but not so on other machines. */
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index c7e6e7b593af10305414ea30f5b944b9d21dd2e2..6246929cf4d7583e5b98e24a6aa7b1f2021431f7 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -344,20 +344,6 @@ dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti)
}
EXPORT_SYMBOL(dump_elf_thread);
-int
-dump_elf_task(elf_greg_t *dest, struct task_struct *task)
-{
- dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task));
- return 1;
-}
-EXPORT_SYMBOL(dump_elf_task);
-
-int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
-{
- memcpy(fpu, task_thread_info(t)->fp, 32 * 8);
- return 1;
-}
-
/*
* Return saved PC of a blocked thread. This assumes the frame
* pointer is the 6th saved long on the kernel stack and that the
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 08e2401cb7e005795a04e169f0c53cf9ed35adb5..4f857d5cbb1410961a78e4ef36cce4561a7ea7af 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -506,16 +506,7 @@ long arch_ptrace(struct task_struct *child, long request,
return ret;
}
-/*
- * Minimal regset support for Alpha.
- *
- * Alpha-specific notes:
- * - Do NOT use ELF_CORE_COPY_REGS(): it uses current_thread_info(),
- * which is wrong for non-current tasks.
- * - dump_elf_task() returns 1 unconditionally in this tree, while
- * regset_get should return 0 on success. So call dump_elf_thread()
- * directly and return membuf_write()'s result.
- */
+/* Ptrace and ELF core dumps share the same Alpha register layouts. */
static int alpha_regset_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
@@ -588,10 +579,8 @@ static int alpha_fpregset_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
- elf_fpregset_t fpregs;
-
- alpha_elf_fpregs_get(target, fpregs);
- return membuf_write(&to, fpregs, sizeof(fpregs));
+ return membuf_write(&to, task_thread_info(target)->fp,
+ sizeof(elf_fpregset_t));
}
enum alpha_regset {
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 10/14] alpha: use generic syscall audit classification
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (8 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 09/14] alpha: remove obsolete core dump register hooks Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 11/14] alpha: use generic ptrace memory writes Magnus Lindholm
` (3 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Replace Alpha's duplicate audit classes and classifier with
AUDIT_GENERIC. Alpha has no compat syscall ABI requiring a private
implementation.
The generic classifier also makes execveat match execute-permission
rules, as execve already does.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/Kconfig | 4 ---
arch/alpha/kernel/Makefile | 1 -
arch/alpha/kernel/audit.c | 62 ----------------------------------------------
3 files changed, 67 deletions(-)
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 19ed083d4f0617218e37a3bac516ec82c5423d7e..014a52e63dec88d72c51c93b3d1c254839ecf33c 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -53,7 +53,6 @@ config ALPHA
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_LD_ORPHAN_WARN
select ARCH_HAVE_NMI_SAFE_CMPXCHG
- select AUDIT_ARCH
select EDAC_SUPPORT
select GENERIC_CPU_VULNERABILITIES
select GENERIC_SMP_IDLE_THREAD
@@ -110,9 +109,6 @@ config PGTABLE_LEVELS
int
default 3
-config AUDIT_ARCH
- bool
-
config STACKTRACE_SUPPORT
def_bool y
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 668556d8496c0c3ee03996cf5a4a0ee56b980891..850f1265cc55db5e0472c37b693dc952bdc75421 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o
obj-$(CONFIG_RTC_DRV_ALPHA) += rtc.o
-obj-$(CONFIG_AUDIT) += audit.o
ifdef CONFIG_ALPHA_GENERIC
diff --git a/arch/alpha/kernel/audit.c b/arch/alpha/kernel/audit.c
deleted file mode 100644
index 3ab04709784a225e1a325cd68f8a1fa3865bd170..0000000000000000000000000000000000000000
--- a/arch/alpha/kernel/audit.c
+++ /dev/null
@@ -1,62 +0,0 @@
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/audit.h>
-#include <asm/unistd.h>
-
-static unsigned dir_class[] = {
-#include <asm-generic/audit_dir_write.h>
-~0U
-};
-
-static unsigned read_class[] = {
-#include <asm-generic/audit_read.h>
-~0U
-};
-
-static unsigned write_class[] = {
-#include <asm-generic/audit_write.h>
-~0U
-};
-
-static unsigned chattr_class[] = {
-#include <asm-generic/audit_change_attr.h>
-~0U
-};
-
-static unsigned signal_class[] = {
-#include <asm-generic/audit_signal.h>
-~0U
-};
-
-int audit_classify_arch(int arch)
-{
- return 0;
-}
-
-int audit_classify_syscall(int abi, unsigned syscall)
-{
- switch(syscall) {
- case __NR_open:
- return AUDITSC_OPEN;
- case __NR_openat:
- return AUDITSC_OPENAT;
- case __NR_execve:
- return AUDITSC_EXECVE;
- case __NR_openat2:
- return AUDITSC_OPENAT2;
- default:
- return AUDITSC_NATIVE;
- }
-}
-
-static int __init audit_classes_init(void)
-{
- audit_register_class(AUDIT_CLASS_WRITE, write_class);
- audit_register_class(AUDIT_CLASS_READ, read_class);
- audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
- audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
- audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
- return 0;
-}
-
-__initcall(audit_classes_init);
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 11/14] alpha: use generic ptrace memory writes
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (9 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 10/14] alpha: use generic syscall audit classification Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 12/14] alpha: use memparse for memory size options Magnus Lindholm
` (2 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Let ptrace_request() handle PTRACE_POKETEXT and PTRACE_POKEDATA,
removing the duplicate calls to generic_ptrace_pokedata(). Keep Alpha's
PEEK handlers for its direct-return syscall convention.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/kernel/ptrace.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 4f857d5cbb1410961a78e4ef36cce4561a7ea7af..18860066156ae7fe5a062095fd2641c4ed0c77de 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -489,12 +489,6 @@ long arch_ptrace(struct task_struct *child, long request,
force_successful_syscall_return();
break;
- /* When I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- ret = generic_ptrace_pokedata(child, addr, data);
- break;
-
case PTRACE_POKEUSR: /* write the specified register */
DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
ret = put_reg(child, addr, data);
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 12/14] alpha: use memparse for memory size options
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (10 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 11/14] alpha: use generic ptrace memory writes Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 13/14] alpha: use generic getrusage for OSF resource accounting Magnus Lindholm
2026-11-03 21:35 ` [PATCH 14/14] alpha: use generic CPU device registration Magnus Lindholm
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Replace the private parser for mem= and gartsize= with memparse(),
preserving page rounding. This also accepts T/P/E suffixes and uses
memparse()'s saturating overflow handling.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/kernel/setup.c | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 4cbcfb1852d51e7aaf37b01a176f4a4280af6dae..28387786cb9f9ad4b587a22a3b0267b825b424c7 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -241,26 +241,6 @@ reserve_std_resources(void)
for ((_cluster) = (memdesc)->cluster, (i) = 0; \
(i) < (memdesc)->numclusters; (i)++, (_cluster)++)
-static unsigned long __init
-get_mem_size_limit(char *s)
-{
- unsigned long end = 0;
- char *from = s;
-
- end = simple_strtoul(from, &from, 0);
- if ( *from == 'K' || *from == 'k' ) {
- end = end << 10;
- from++;
- } else if ( *from == 'M' || *from == 'm' ) {
- end = end << 20;
- from++;
- } else if ( *from == 'G' || *from == 'g' ) {
- end = end << 30;
- from++;
- }
- return end >> PAGE_SHIFT; /* Return the PFN of the limit. */
-}
-
#ifdef CONFIG_BLK_DEV_INITRD
void * __init
move_initrd(unsigned long mem_limit)
@@ -486,7 +466,7 @@ setup_arch(char **cmdline_p)
continue;
}
if (strncmp(p, "mem=", 4) == 0) {
- mem_size_limit = get_mem_size_limit(p+4);
+ mem_size_limit = memparse(p + 4, NULL) >> PAGE_SHIFT;
continue;
}
if (strncmp(p, "srmcons", 7) == 0) {
@@ -499,7 +479,7 @@ setup_arch(char **cmdline_p)
}
if (strncmp(p, "gartsize=", 9) == 0) {
alpha_agpgart_size =
- get_mem_size_limit(p+9) << PAGE_SHIFT;
+ memparse(p + 9, NULL) & PAGE_MASK;
continue;
}
#ifdef CONFIG_VERBOSE_MCHECK
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 13/14] alpha: use generic getrusage for OSF resource accounting
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (11 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 12/14] alpha: use memparse for memory size options Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
2026-11-03 21:35 ` [PATCH 14/14] alpha: use generic CPU device registration Magnus Lindholm
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Use getrusage() for OSF resource accounting. This intentionally aligns
osf_getrusage() accounting with getrusage(2): RUSAGE_SELF covers the whole
thread group rather than only the calling thread, and ru_maxrss, block
I/O and context-switch counts are populated instead of remaining zero.
CPU times use the generic microsecond conversion instead of the previous
jiffy rounding.
Keep the OSF structure layout and the existing RUSAGE_SELF/RUSAGE_CHILDREN
selector restriction. Share result conversion with osf_wait4() and remove
the jiffy-based time conversion.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/kernel/osf_sys.c | 56 ++++++++++++++-------------------------------
1 file changed, 17 insertions(+), 39 deletions(-)
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 61d8061762133f5e128d8538cf104dfede57ea6d..c08796f627332e4562a30557dee700052d03c0e7 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -15,7 +15,7 @@
#include <linux/sched/signal.h>
#include <linux/sched/mm.h>
#include <linux/sched/task_stack.h>
-#include <linux/sched/cputime.h>
+#include <linux/resource.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
@@ -960,13 +960,6 @@ put_tv_to_tv32(struct timeval32 __user *o, struct __kernel_old_timeval *i)
sizeof(struct timeval32));
}
-static inline void
-jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value)
-{
- value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
- value->tv_sec = jiffies / HZ;
-}
-
SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv,
struct timezone __user *, tz)
{
@@ -1062,37 +1055,27 @@ struct rusage32 {
long ru_nivcsw; /* involuntary " */
};
+static int put_rusage32(struct rusage32 __user *ru, struct rusage *r)
+{
+ if (put_tv_to_tv32(&ru->ru_utime, &r->ru_utime))
+ return -EFAULT;
+ if (put_tv_to_tv32(&ru->ru_stime, &r->ru_stime))
+ return -EFAULT;
+ if (copy_to_user(&ru->ru_maxrss, &r->ru_maxrss,
+ sizeof(*ru) - offsetof(struct rusage32, ru_maxrss)))
+ return -EFAULT;
+ return 0;
+}
+
SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru)
{
- struct rusage32 r;
- u64 utime, stime;
- unsigned long utime_jiffies, stime_jiffies;
+ struct rusage r;
if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
return -EINVAL;
- memset(&r, 0, sizeof(r));
- switch (who) {
- case RUSAGE_SELF:
- task_cputime(current, &utime, &stime);
- utime_jiffies = nsecs_to_jiffies(utime);
- stime_jiffies = nsecs_to_jiffies(stime);
- jiffies_to_timeval32(utime_jiffies, &r.ru_utime);
- jiffies_to_timeval32(stime_jiffies, &r.ru_stime);
- r.ru_minflt = current->min_flt;
- r.ru_majflt = current->maj_flt;
- break;
- case RUSAGE_CHILDREN:
- utime_jiffies = nsecs_to_jiffies(current->signal->cutime);
- stime_jiffies = nsecs_to_jiffies(current->signal->cstime);
- jiffies_to_timeval32(utime_jiffies, &r.ru_utime);
- jiffies_to_timeval32(stime_jiffies, &r.ru_stime);
- r.ru_minflt = current->signal->cmin_flt;
- r.ru_majflt = current->signal->cmaj_flt;
- break;
- }
-
- return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
+ getrusage(current, who, &r);
+ return put_rusage32(ru, &r);
}
SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
@@ -1104,12 +1087,7 @@ SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
return err;
if (!ur)
return err;
- if (put_tv_to_tv32(&ur->ru_utime, &r.ru_utime))
- return -EFAULT;
- if (put_tv_to_tv32(&ur->ru_stime, &r.ru_stime))
- return -EFAULT;
- if (copy_to_user(&ur->ru_maxrss, &r.ru_maxrss,
- sizeof(struct rusage32) - offsetof(struct rusage32, ru_maxrss)))
+ if (put_rusage32(ur, &r))
return -EFAULT;
return err;
}
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 14/14] alpha: use generic CPU device registration
2026-11-03 21:35 [PATCH 00/14] alpha: fix entry bugs and consolidate generic helpers Magnus Lindholm
` (12 preceding siblings ...)
2026-11-03 21:35 ` [PATCH 13/14] alpha: use generic getrusage for OSF resource accounting Magnus Lindholm
@ 2026-11-03 21:35 ` Magnus Lindholm
13 siblings, 0 replies; 15+ messages in thread
From: Magnus Lindholm @ 2026-11-03 21:35 UTC (permalink / raw)
To: richard.henderson, mattst88, linux-kernel, linux-alpha; +Cc: linmag7
Select GENERIC_CPU_DEVICES and remove the private registration initcall.
Alpha keeps its possible and present CPU masks in sync, and the generic
path registers CPU devices after SMP setup using the same register_cpu()
helper.
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/alpha/Kconfig | 1 +
arch/alpha/kernel/setup.c | 17 -----------------
2 files changed, 1 insertion(+), 17 deletions(-)
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 014a52e63dec88d72c51c93b3d1c254839ecf33c..6ccb2d2303269661eb36ba4892e3026bf595f8a7 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -54,6 +54,7 @@ config ALPHA
select ARCH_WANT_LD_ORPHAN_WARN
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select EDAC_SUPPORT
+ select GENERIC_CPU_DEVICES
select GENERIC_CPU_VULNERABILITIES
select GENERIC_SMP_IDLE_THREAD
select HAS_IOPORT
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 28387786cb9f9ad4b587a22a3b0267b825b424c7..9fda01b73b18414c8d9c12903660024bfc0af94c 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -17,7 +17,6 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/slab.h>
#include <linux/user.h>
#include <linux/screen_info.h>
#include <linux/delay.h>
@@ -366,22 +365,6 @@ int page_is_ram(unsigned long pfn)
return 0;
}
-static int __init
-register_cpus(void)
-{
- int i;
-
- for_each_possible_cpu(i) {
- struct cpu *p = kzalloc_obj(*p);
- if (!p)
- return -ENOMEM;
- register_cpu(p, i);
- }
- return 0;
-}
-
-arch_initcall(register_cpus);
-
#ifdef CONFIG_MAGIC_SYSRQ
static void sysrq_reboot_handler(u8 unused)
{
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread