mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-30 13:52:50 +01:00
Add a user_regset_view for Alpha and switch ELF core dumping to CORE_DUMP_USE_REGSET. General-purpose registers are exported in ELF gregs layout, including callee-saved registers and a correct user stack pointer. The user stack pointer is not preserved in pt_regs on Alpha, so expose it from the PCB, or via rdusp() for the current task, when building the ELF register image. This makes the user stack pointer consistent for core dumps, ptrace regsets, and PTRACE_GET_SYSCALL_INFO. Implement regset get/set callbacks for both NT_PRSTATUS and NT_PRFPREG. The callbacks translate between Alpha's pt_regs/thread state and the ELF-visible register layouts, while the common ptrace regset code handles PTRACE_GETREGSET and PTRACE_SETREGSET iovec semantics. This avoids duplicating subtle short-buffer and oversized-buffer behavior in arch_ptrace(). With these changes Alpha satisfies the requirements for HAVE_ARCH_TRACEHOOK and selects it, enabling generic tracehook and ptrace syscall-info code paths without changing the existing syscall entry ABI. Reviewed-by: Matt Turner <[email protected]> Tested-by: Matt Turner <[email protected]> Signed-off-by: Magnus Lindholm <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Magnus Lindholm <[email protected]>
114 lines
3.0 KiB
C
114 lines
3.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_ALPHA_SYSCALL_H
|
|
#define _ASM_ALPHA_SYSCALL_H
|
|
|
|
#include <uapi/linux/audit.h>
|
|
#include <linux/audit.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/types.h>
|
|
#include <asm/ptrace.h>
|
|
|
|
static inline int syscall_get_arch(struct task_struct *task)
|
|
{
|
|
return AUDIT_ARCH_ALPHA;
|
|
}
|
|
|
|
static inline long syscall_get_return_value(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
return regs->r19 ? -(long)regs->r0 : (long)regs->r0;
|
|
}
|
|
|
|
static inline long syscall_get_error(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
return regs->r19 ? -(long)regs->r0 : 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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).
|
|
*/
|
|
|
|
static inline long syscall_get_nr(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
return (long)regs->r1;
|
|
}
|
|
|
|
static inline void syscall_set_nr(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
long nr)
|
|
{
|
|
regs->r1 = (unsigned long)nr;
|
|
}
|
|
|
|
/*
|
|
* Syscall arguments:
|
|
* regs->r16..regs->r21 carry up to 6 syscall arguments on entry.
|
|
* Note: regs->r19 is also used as "a3" (error flag) on syscall return.
|
|
*/
|
|
|
|
static inline void syscall_get_arguments(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
unsigned long *args)
|
|
{
|
|
args[0] = regs->r16;
|
|
args[1] = regs->r17;
|
|
args[2] = regs->r18;
|
|
args[3] = regs->r19;
|
|
args[4] = regs->r20;
|
|
args[5] = regs->r21;
|
|
}
|
|
|
|
static inline void syscall_set_arguments(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
const unsigned long *args)
|
|
{
|
|
regs->r16 = args[0];
|
|
regs->r17 = args[1];
|
|
regs->r18 = args[2];
|
|
regs->r19 = args[3];
|
|
regs->r20 = args[4];
|
|
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().
|
|
*/
|
|
|
|
static inline void syscall_set_return_value(struct task_struct *task,
|
|
struct pt_regs *regs,
|
|
int error, long val)
|
|
{
|
|
|
|
if (error) {
|
|
/* error is negative errno in this tree */
|
|
regs->r0 = (unsigned long)(-error); /* positive errno */
|
|
regs->r19 = 1; /* a3 = error */
|
|
} else {
|
|
regs->r0 = (unsigned long)val;
|
|
regs->r19 = 0; /* a3 = success */
|
|
}
|
|
}
|
|
|
|
/* Restore the original syscall nr after seccomp/ptrace modified regs->r1. */
|
|
static inline void syscall_rollback(struct task_struct *task,
|
|
struct pt_regs *regs)
|
|
{
|
|
regs->r1 = regs->r2;
|
|
}
|
|
|
|
#endif /* _ASM_ALPHA_SYSCALL_H */
|