Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Access to user system call parameters and results
0003  *
0004  * This file is subject to the terms and conditions of the GNU General Public
0005  * License.  See the file "COPYING" in the main directory of this archive
0006  * for more details.
0007  *
0008  * See asm-generic/syscall.h for descriptions of what we must do here.
0009  *
0010  * Copyright (C) 2012 Ralf Baechle <ralf@linux-mips.org>
0011  */
0012 
0013 #ifndef __ASM_MIPS_SYSCALL_H
0014 #define __ASM_MIPS_SYSCALL_H
0015 
0016 #include <linux/compiler.h>
0017 #include <uapi/linux/audit.h>
0018 #include <linux/elf-em.h>
0019 #include <linux/kernel.h>
0020 #include <linux/sched.h>
0021 #include <linux/uaccess.h>
0022 #include <asm/ptrace.h>
0023 #include <asm/unistd.h>
0024 
0025 #ifndef __NR_syscall /* Only defined if _MIPS_SIM == _MIPS_SIM_ABI32 */
0026 #define __NR_syscall 4000
0027 #endif
0028 
0029 static inline bool mips_syscall_is_indirect(struct task_struct *task,
0030                         struct pt_regs *regs)
0031 {
0032     /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
0033     return (IS_ENABLED(CONFIG_32BIT) ||
0034         test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
0035         (regs->regs[2] == __NR_syscall);
0036 }
0037 
0038 static inline long syscall_get_nr(struct task_struct *task,
0039                   struct pt_regs *regs)
0040 {
0041     return current_thread_info()->syscall;
0042 }
0043 
0044 static inline void mips_syscall_update_nr(struct task_struct *task,
0045                       struct pt_regs *regs)
0046 {
0047     /*
0048      * v0 is the system call number, except for O32 ABI syscall(), where it
0049      * ends up in a0.
0050      */
0051     if (mips_syscall_is_indirect(task, regs))
0052         task_thread_info(task)->syscall = regs->regs[4];
0053     else
0054         task_thread_info(task)->syscall = regs->regs[2];
0055 }
0056 
0057 static inline void mips_get_syscall_arg(unsigned long *arg,
0058     struct task_struct *task, struct pt_regs *regs, unsigned int n)
0059 {
0060     unsigned long usp __maybe_unused = regs->regs[29];
0061 
0062     switch (n) {
0063     case 0: case 1: case 2: case 3:
0064         *arg = regs->regs[4 + n];
0065 
0066         return;
0067 
0068 #ifdef CONFIG_32BIT
0069     case 4: case 5: case 6: case 7:
0070         get_user(*arg, (int *)usp + n);
0071         return;
0072 #endif
0073 
0074 #ifdef CONFIG_64BIT
0075     case 4: case 5: case 6: case 7:
0076 #ifdef CONFIG_MIPS32_O32
0077         if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
0078             get_user(*arg, (int *)usp + n);
0079         else
0080 #endif
0081             *arg = regs->regs[4 + n];
0082 
0083         return;
0084 #endif
0085 
0086     default:
0087         BUG();
0088     }
0089 
0090     unreachable();
0091 }
0092 
0093 static inline long syscall_get_error(struct task_struct *task,
0094                      struct pt_regs *regs)
0095 {
0096     return regs->regs[7] ? -regs->regs[2] : 0;
0097 }
0098 
0099 static inline long syscall_get_return_value(struct task_struct *task,
0100                         struct pt_regs *regs)
0101 {
0102     return regs->regs[2];
0103 }
0104 
0105 static inline void syscall_rollback(struct task_struct *task,
0106                     struct pt_regs *regs)
0107 {
0108     /* Do nothing */
0109 }
0110 
0111 static inline void syscall_set_return_value(struct task_struct *task,
0112                         struct pt_regs *regs,
0113                         int error, long val)
0114 {
0115     if (error) {
0116         regs->regs[2] = -error;
0117         regs->regs[7] = 1;
0118     } else {
0119         regs->regs[2] = val;
0120         regs->regs[7] = 0;
0121     }
0122 }
0123 
0124 static inline void syscall_get_arguments(struct task_struct *task,
0125                      struct pt_regs *regs,
0126                      unsigned long *args)
0127 {
0128     unsigned int i = 0;
0129     unsigned int n = 6;
0130 
0131     /* O32 ABI syscall() */
0132     if (mips_syscall_is_indirect(task, regs))
0133         i++;
0134 
0135     while (n--)
0136         mips_get_syscall_arg(args++, task, regs, i++);
0137 }
0138 
0139 extern const unsigned long sys_call_table[];
0140 extern const unsigned long sys32_call_table[];
0141 extern const unsigned long sysn32_call_table[];
0142 
0143 static inline int syscall_get_arch(struct task_struct *task)
0144 {
0145     int arch = AUDIT_ARCH_MIPS;
0146 #ifdef CONFIG_64BIT
0147     if (!test_tsk_thread_flag(task, TIF_32BIT_REGS)) {
0148         arch |= __AUDIT_ARCH_64BIT;
0149         /* N32 sets only TIF_32BIT_ADDR */
0150         if (test_tsk_thread_flag(task, TIF_32BIT_ADDR))
0151             arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32;
0152     }
0153 #endif
0154 #if defined(__LITTLE_ENDIAN)
0155     arch |=  __AUDIT_ARCH_LE;
0156 #endif
0157     return arch;
0158 }
0159 
0160 #endif  /* __ASM_MIPS_SYSCALL_H */