Files
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/[email protected]
Signed-off-by: Dmitry V. Levin <[email protected]>
Tested-by: Charlie Jenkins <[email protected]>
Reviewed-by: Charlie Jenkins <[email protected]>
Acked-by: Helge Deller <[email protected]> # parisc
Reviewed-by: Maciej W. Rozycki <[email protected]> # mips
Cc: Alexander Gordeev <[email protected]>
Cc: Alexey Gladkov (Intel) <[email protected]>
Cc: Andreas Larsson <[email protected]>
Cc: anton ivanov <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Borislav Betkov <[email protected]>
Cc: Brian Cain <[email protected]>
Cc: Christian Borntraeger <[email protected]>
Cc: Christian Zankel <[email protected]>
Cc: Christophe Leroy <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Davide Berardi <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Dinh Nguyen <[email protected]>
Cc: Eugene Syromiatnikov <[email protected]>
Cc: Eugene Syromyatnikov <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: Guo Ren <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Huacai Chen <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Johannes Berg <[email protected]>
Cc: John Paul Adrian Glaubitz <[email protected]>
Cc: Jonas Bonn <[email protected]>
Cc: Madhavan Srinivasan <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Michael Ellerman <[email protected]>
Cc: Michal Simek <[email protected]>
Cc: Mike Frysinger <[email protected]>
Cc: Naveen N Rao <[email protected]>
Cc: Nicholas Piggin <[email protected]>
Cc: Oleg Nesterov <[email protected]>
Cc: Renzo Davoi <[email protected]>
Cc: Richard Weinberger <[email protected]>
Cc: Rich Felker <[email protected]>
Cc: Russel King <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: Stafford Horne <[email protected]>
Cc: Stefan Kristiansson <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Thomas Gleinxer <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Cc: Vineet Gupta <[email protected]>
Cc: WANG Xuerui <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Yoshinori Sato <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
2025-05-11 17:48:15 -07:00

188 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 <[email protected]>
*/
#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 */