Contributors: 11
Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
Ralf Baechle |
459 |
58.47% |
8 |
26.67% |
Dmitry V. Levin |
125 |
15.92% |
6 |
20.00% |
Markos Chandras |
79 |
10.06% |
6 |
20.00% |
James Hogan |
73 |
9.30% |
1 |
3.33% |
Steven Rostedt |
24 |
3.06% |
1 |
3.33% |
Linus Torvalds (pre-git) |
8 |
1.02% |
1 |
3.33% |
David Woodhouse |
7 |
0.89% |
1 |
3.33% |
Nathan Chancellor |
5 |
0.64% |
1 |
3.33% |
Eric Paris |
3 |
0.38% |
3 |
10.00% |
Lars Persson |
1 |
0.13% |
1 |
3.33% |
Masahiro Yamada |
1 |
0.13% |
1 |
3.33% |
Total |
785 |
|
30 |
|
/*
* 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 */