linux/arch/mips/include/asm/syscall.h
<<
>>
Prefs
   1/*
   2 * Access to user system call parameters and results
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * See asm-generic/syscall.h for descriptions of what we must do here.
   9 *
  10 * Copyright (C) 2012 Ralf Baechle <ralf@linux-mips.org>
  11 */
  12
  13#ifndef __ASM_MIPS_SYSCALL_H
  14#define __ASM_MIPS_SYSCALL_H
  15
  16#include <linux/compiler.h>
  17#include <uapi/linux/audit.h>
  18#include <linux/elf-em.h>
  19#include <linux/kernel.h>
  20#include <linux/sched.h>
  21#include <linux/uaccess.h>
  22#include <asm/ptrace.h>
  23#include <asm/unistd.h>
  24
  25#ifndef __NR_syscall /* Only defined if _MIPS_SIM == _MIPS_SIM_ABI32 */
  26#define __NR_syscall 4000
  27#endif
  28
  29static inline bool mips_syscall_is_indirect(struct task_struct *task,
  30                                            struct pt_regs *regs)
  31{
  32        /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
  33        return (IS_ENABLED(CONFIG_32BIT) ||
  34                test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
  35                (regs->regs[2] == __NR_syscall);
  36}
  37
  38static inline long syscall_get_nr(struct task_struct *task,
  39                                  struct pt_regs *regs)
  40{
  41        return current_thread_info()->syscall;
  42}
  43
  44static inline void mips_syscall_update_nr(struct task_struct *task,
  45                                          struct pt_regs *regs)
  46{
  47        /*
  48         * v0 is the system call number, except for O32 ABI syscall(), where it
  49         * ends up in a0.
  50         */
  51        if (mips_syscall_is_indirect(task, regs))
  52                task_thread_info(task)->syscall = regs->regs[4];
  53        else
  54                task_thread_info(task)->syscall = regs->regs[2];
  55}
  56
  57static inline void mips_get_syscall_arg(unsigned long *arg,
  58        struct task_struct *task, struct pt_regs *regs, unsigned int n)
  59{
  60        unsigned long usp __maybe_unused = regs->regs[29];
  61
  62        switch (n) {
  63        case 0: case 1: case 2: case 3:
  64                *arg = regs->regs[4 + n];
  65
  66                return;
  67
  68#ifdef CONFIG_32BIT
  69        case 4: case 5: case 6: case 7:
  70                get_user(*arg, (int *)usp + n);
  71                return;
  72#endif
  73
  74#ifdef CONFIG_64BIT
  75        case 4: case 5: case 6: case 7:
  76#ifdef CONFIG_MIPS32_O32
  77                if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
  78                        get_user(*arg, (int *)usp + n);
  79                else
  80#endif
  81                        *arg = regs->regs[4 + n];
  82
  83                return;
  84#endif
  85
  86        default:
  87                BUG();
  88        }
  89
  90        unreachable();
  91}
  92
  93static inline long syscall_get_error(struct task_struct *task,
  94                                     struct pt_regs *regs)
  95{
  96        return regs->regs[7] ? -regs->regs[2] : 0;
  97}
  98
  99static inline long syscall_get_return_value(struct task_struct *task,
 100                                            struct pt_regs *regs)
 101{
 102        return regs->regs[2];
 103}
 104
 105static inline void syscall_rollback(struct task_struct *task,
 106                                    struct pt_regs *regs)
 107{
 108        /* Do nothing */
 109}
 110
 111static inline void syscall_set_return_value(struct task_struct *task,
 112                                            struct pt_regs *regs,
 113                                            int error, long val)
 114{
 115        if (error) {
 116                regs->regs[2] = -error;
 117                regs->regs[7] = 1;
 118        } else {
 119                regs->regs[2] = val;
 120                regs->regs[7] = 0;
 121        }
 122}
 123
 124static inline void syscall_get_arguments(struct task_struct *task,
 125                                         struct pt_regs *regs,
 126                                         unsigned long *args)
 127{
 128        unsigned int i = 0;
 129        unsigned int n = 6;
 130
 131        /* O32 ABI syscall() */
 132        if (mips_syscall_is_indirect(task, regs))
 133                i++;
 134
 135        while (n--)
 136                mips_get_syscall_arg(args++, task, regs, i++);
 137}
 138
 139extern const unsigned long sys_call_table[];
 140extern const unsigned long sys32_call_table[];
 141extern const unsigned long sysn32_call_table[];
 142
 143static inline int syscall_get_arch(struct task_struct *task)
 144{
 145        int arch = AUDIT_ARCH_MIPS;
 146#ifdef CONFIG_64BIT
 147        if (!test_tsk_thread_flag(task, TIF_32BIT_REGS)) {
 148                arch |= __AUDIT_ARCH_64BIT;
 149                /* N32 sets only TIF_32BIT_ADDR */
 150                if (test_tsk_thread_flag(task, TIF_32BIT_ADDR))
 151                        arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32;
 152        }
 153#endif
 154#if defined(__LITTLE_ENDIAN)
 155        arch |=  __AUDIT_ARCH_LE;
 156#endif
 157        return arch;
 158}
 159
 160#endif  /* __ASM_MIPS_SYSCALL_H */
 161