linux/arch/mips/include/asm/syscall.h
Dmitry V. Levin cc6622730b syscall.h: introduce syscall_set_nr()
Similar to syscall_set_arguments() that complements
syscall_get_arguments(), introduce syscall_set_nr() that complements
syscall_get_nr().

syscall_set_nr() is going to be needed along with syscall_set_arguments()
on all HAVE_ARCH_TRACEHOOK architectures to implement
PTRACE_SET_SYSCALL_INFO API.

Link: https://lkml.kernel.org/r/20250303112020.GD24170@strace.io
Signed-off-by: Dmitry V. Levin <ldv@strace.io>
Tested-by: Charlie Jenkins <charlie@rivosinc.com>
Reviewed-by: Charlie Jenkins <charlie@rivosinc.com>
Acked-by: Helge Deller <deller@gmx.de> # parisc
Reviewed-by: Maciej W. Rozycki <macro@orcam.me.uk> # mips
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Alexey Gladkov (Intel) <legion@kernel.org>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: anton ivanov <anton.ivanov@cambridgegreys.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Borislav Betkov <bp@alien8.de>
Cc: Brian Cain <bcain@quicinc.com>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Christian Zankel <chris@zankel.net>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Davide Berardi <berardi.dav@gmail.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Dinh Nguyen <dinguyen@kernel.org>
Cc: Eugene Syromiatnikov <esyr@redhat.com>
Cc: Eugene Syromyatnikov <evgsyr@gmail.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Guo Ren <guoren@kernel.org>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Simek <monstr@monstr.eu>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Naveen N Rao <naveen@kernel.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Renzo Davoi <renzo@cs.unibo.it>
Cc: Richard Weinberger <richard@nod.at>
Cc: Rich Felker <dalias@libc.org>
Cc: Russel King <linux@armlinux.org.uk>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Stafford Horne <shorne@gmail.com>
Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Thomas Gleinxer <tglx@linutronix.de>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Vineet Gupta <vgupta@kernel.org>
Cc: WANG Xuerui <kernel@xen0n.name>
Cc: Will Deacon <will@kernel.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-05-11 17:48:15 -07:00

187 lines
4.5 KiB
C

/*
* Access to user system call parameters and results
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* See asm-generic/syscall.h for descriptions of what we must do here.
*
* Copyright (C) 2012 Ralf Baechle <ralf@linux-mips.org>
*/
#ifndef __ASM_MIPS_SYSCALL_H
#define __ASM_MIPS_SYSCALL_H
#include <linux/compiler.h>
#include <uapi/linux/audit.h>
#include <linux/elf-em.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/ptrace.h>
#include <asm/unistd.h>
#ifndef __NR_syscall /* Only defined if _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_syscall 4000
#endif
static inline bool mips_syscall_is_indirect(struct task_struct *task,
struct pt_regs *regs)
{
/* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
return (IS_ENABLED(CONFIG_32BIT) ||
test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
(regs->regs[2] == __NR_syscall);
}
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
return task_thread_info(task)->syscall;
}
static inline void syscall_set_nr(struct task_struct *task,
struct pt_regs *regs,
int nr)
{
/*
* New syscall number has to be assigned to regs[2] because
* it is loaded from there unconditionally after return from
* syscall_trace_enter() invocation.
*
* Consequently, if the syscall was indirect and nr != __NR_syscall,
* then after this assignment the syscall will cease to be indirect.
*/
task_thread_info(task)->syscall = regs->regs[2] = nr;
}
static inline void mips_syscall_update_nr(struct task_struct *task,
struct pt_regs *regs)
{
/*
* v0 is the system call number, except for O32 ABI syscall(), where it
* ends up in a0.
*/
if (mips_syscall_is_indirect(task, regs))
task_thread_info(task)->syscall = regs->regs[4];
else
task_thread_info(task)->syscall = regs->regs[2];
}
static inline void mips_get_syscall_arg(unsigned long *arg,
struct task_struct *task, struct pt_regs *regs, unsigned int n)
{
#ifdef CONFIG_32BIT
switch (n) {
case 0: case 1: case 2: case 3:
*arg = regs->regs[4 + n];
return;
case 4: case 5: case 6: case 7:
*arg = regs->args[n];
return;
}
#else
*arg = regs->regs[4 + n];
if ((IS_ENABLED(CONFIG_MIPS32_O32) &&
test_tsk_thread_flag(task, TIF_32BIT_REGS)))
*arg = (unsigned int)*arg;
#endif
}
static inline void mips_set_syscall_arg(unsigned long *arg,
struct task_struct *task, struct pt_regs *regs, unsigned int n)
{
#ifdef CONFIG_32BIT
switch (n) {
case 0: case 1: case 2: case 3:
regs->regs[4 + n] = *arg;
return;
case 4: case 5: case 6: case 7:
*arg = regs->args[n] = *arg;
return;
}
#else
regs->regs[4 + n] = *arg;
#endif
}
static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
return regs->regs[7] ? -regs->regs[2] : 0;
}
static inline long syscall_get_return_value(struct task_struct *task,
struct pt_regs *regs)
{
return regs->regs[2];
}
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
/* Do nothing */
}
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
if (error) {
regs->regs[2] = -error;
regs->regs[7] = 1;
} else {
regs->regs[2] = val;
regs->regs[7] = 0;
}
}
static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned long *args)
{
unsigned int i = 0;
unsigned int n = 6;
/* O32 ABI syscall() */
if (mips_syscall_is_indirect(task, regs))
i++;
while (n--)
mips_get_syscall_arg(args++, task, regs, i++);
}
static inline void syscall_set_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned long *args)
{
unsigned int i = 0;
unsigned int n = 6;
while (n--)
mips_set_syscall_arg(args++, task, regs, i++);
}
extern const unsigned long sys_call_table[];
extern const unsigned long sys32_call_table[];
extern const unsigned long sysn32_call_table[];
static inline int syscall_get_arch(struct task_struct *task)
{
int arch = AUDIT_ARCH_MIPS;
#ifdef CONFIG_64BIT
if (!test_tsk_thread_flag(task, TIF_32BIT_REGS)) {
arch |= __AUDIT_ARCH_64BIT;
/* N32 sets only TIF_32BIT_ADDR */
if (test_tsk_thread_flag(task, TIF_32BIT_ADDR))
arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32;
}
#endif
#if defined(__LITTLE_ENDIAN)
arch |= __AUDIT_ARCH_LE;
#endif
return arch;
}
#endif /* __ASM_MIPS_SYSCALL_H */