linux/arch/mips/kernel/syscall.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1995, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
   7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
   8 * Copyright (C) 2001 MIPS Technologies, Inc.
   9 */
  10#include <linux/capability.h>
  11#include <linux/errno.h>
  12#include <linux/linkage.h>
  13#include <linux/fs.h>
  14#include <linux/smp.h>
  15#include <linux/ptrace.h>
  16#include <linux/string.h>
  17#include <linux/syscalls.h>
  18#include <linux/file.h>
  19#include <linux/utsname.h>
  20#include <linux/unistd.h>
  21#include <linux/sem.h>
  22#include <linux/msg.h>
  23#include <linux/shm.h>
  24#include <linux/compiler.h>
  25#include <linux/ipc.h>
  26#include <linux/uaccess.h>
  27#include <linux/slab.h>
  28#include <linux/elf.h>
  29#include <linux/sched/task_stack.h>
  30
  31#include <asm/asm.h>
  32#include <asm/asm-eva.h>
  33#include <asm/branch.h>
  34#include <asm/cachectl.h>
  35#include <asm/cacheflush.h>
  36#include <asm/asm-offsets.h>
  37#include <asm/signal.h>
  38#include <asm/sim.h>
  39#include <asm/shmparam.h>
  40#include <asm/sync.h>
  41#include <asm/sysmips.h>
  42#include <asm/switch_to.h>
  43
  44/*
  45 * For historic reasons the pipe(2) syscall on MIPS has an unusual calling
  46 * convention.  It returns results in registers $v0 / $v1 which means there
  47 * is no need for it to do verify the validity of a userspace pointer
  48 * argument.  Historically that used to be expensive in Linux.  These days
  49 * the performance advantage is negligible.
  50 */
  51asmlinkage int sysm_pipe(void)
  52{
  53        int fd[2];
  54        int error = do_pipe_flags(fd, 0);
  55        if (error)
  56                return error;
  57        current_pt_regs()->regs[3] = fd[1];
  58        return fd[0];
  59}
  60
  61SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
  62        unsigned long, prot, unsigned long, flags, unsigned long,
  63        fd, off_t, offset)
  64{
  65        if (offset & ~PAGE_MASK)
  66                return -EINVAL;
  67        return ksys_mmap_pgoff(addr, len, prot, flags, fd,
  68                               offset >> PAGE_SHIFT);
  69}
  70
  71SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
  72        unsigned long, prot, unsigned long, flags, unsigned long, fd,
  73        unsigned long, pgoff)
  74{
  75        if (pgoff & (~PAGE_MASK >> 12))
  76                return -EINVAL;
  77
  78        return ksys_mmap_pgoff(addr, len, prot, flags, fd,
  79                               pgoff >> (PAGE_SHIFT - 12));
  80}
  81
  82save_static_function(sys_fork);
  83save_static_function(sys_clone);
  84save_static_function(sys_clone3);
  85
  86SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
  87{
  88        struct thread_info *ti = task_thread_info(current);
  89
  90        ti->tp_value = addr;
  91        if (cpu_has_userlocal)
  92                write_c0_userlocal(addr);
  93
  94        return 0;
  95}
  96
  97static inline int mips_atomic_set(unsigned long addr, unsigned long new)
  98{
  99        unsigned long old, tmp;
 100        struct pt_regs *regs;
 101        unsigned int err;
 102
 103        if (unlikely(addr & 3))
 104                return -EINVAL;
 105
 106        if (unlikely(!access_ok((const void __user *)addr, 4)))
 107                return -EINVAL;
 108
 109        if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) {
 110                __asm__ __volatile__ (
 111                "       .set    push                                    \n"
 112                "       .set    arch=r4000                              \n"
 113                "       li      %[err], 0                               \n"
 114                "1:     ll      %[old], (%[addr])                       \n"
 115                "       move    %[tmp], %[new]                          \n"
 116                "2:     sc      %[tmp], (%[addr])                       \n"
 117                "       beqzl   %[tmp], 1b                              \n"
 118                "3:                                                     \n"
 119                "       .insn                                           \n"
 120                "       .section .fixup,\"ax\"                          \n"
 121                "4:     li      %[err], %[efault]                       \n"
 122                "       j       3b                                      \n"
 123                "       .previous                                       \n"
 124                "       .section __ex_table,\"a\"                       \n"
 125                "       "STR(PTR)"      1b, 4b                          \n"
 126                "       "STR(PTR)"      2b, 4b                          \n"
 127                "       .previous                                       \n"
 128                "       .set    pop                                     \n"
 129                : [old] "=&r" (old),
 130                  [err] "=&r" (err),
 131                  [tmp] "=&r" (tmp)
 132                : [addr] "r" (addr),
 133                  [new] "r" (new),
 134                  [efault] "i" (-EFAULT)
 135                : "memory");
 136        } else if (cpu_has_llsc) {
 137                __asm__ __volatile__ (
 138                "       .set    push                                    \n"
 139                "       .set    "MIPS_ISA_ARCH_LEVEL"                   \n"
 140                "       li      %[err], 0                               \n"
 141                "1:                                                     \n"
 142                "       " __SYNC(full, loongson3_war) "                 \n"
 143                user_ll("%[old]", "(%[addr])")
 144                "       move    %[tmp], %[new]                          \n"
 145                "2:                                                     \n"
 146                user_sc("%[tmp]", "(%[addr])")
 147                "       beqz    %[tmp], 1b                              \n"
 148                "3:                                                     \n"
 149                "       .insn                                           \n"
 150                "       .section .fixup,\"ax\"                          \n"
 151                "5:     li      %[err], %[efault]                       \n"
 152                "       j       3b                                      \n"
 153                "       .previous                                       \n"
 154                "       .section __ex_table,\"a\"                       \n"
 155                "       "STR(PTR)"      1b, 5b                          \n"
 156                "       "STR(PTR)"      2b, 5b                          \n"
 157                "       .previous                                       \n"
 158                "       .set    pop                                     \n"
 159                : [old] "=&r" (old),
 160                  [err] "=&r" (err),
 161                  [tmp] "=&r" (tmp)
 162                : [addr] "r" (addr),
 163                  [new] "r" (new),
 164                  [efault] "i" (-EFAULT)
 165                : "memory");
 166        } else {
 167                do {
 168                        preempt_disable();
 169                        ll_bit = 1;
 170                        ll_task = current;
 171                        preempt_enable();
 172
 173                        err = __get_user(old, (unsigned int *) addr);
 174                        err |= __put_user(new, (unsigned int *) addr);
 175                        if (err)
 176                                break;
 177                        rmb();
 178                } while (!ll_bit);
 179        }
 180
 181        if (unlikely(err))
 182                return err;
 183
 184        regs = current_pt_regs();
 185        regs->regs[2] = old;
 186        regs->regs[7] = 0;      /* No error */
 187
 188        /*
 189         * Don't let your children do this ...
 190         */
 191        __asm__ __volatile__(
 192        "       move    $29, %0                                         \n"
 193        "       j       syscall_exit                                    \n"
 194        : /* no outputs */
 195        : "r" (regs));
 196
 197        /* unreached.  Honestly.  */
 198        unreachable();
 199}
 200
 201/*
 202 * mips_atomic_set() normally returns directly via syscall_exit potentially
 203 * clobbering static registers, so be sure to preserve them.
 204 */
 205save_static_function(sys_sysmips);
 206
 207SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
 208{
 209        switch (cmd) {
 210        case MIPS_ATOMIC_SET:
 211                return mips_atomic_set(arg1, arg2);
 212
 213        case MIPS_FIXADE:
 214                if (arg1 & ~3)
 215                        return -EINVAL;
 216
 217                if (arg1 & 1)
 218                        set_thread_flag(TIF_FIXADE);
 219                else
 220                        clear_thread_flag(TIF_FIXADE);
 221                if (arg1 & 2)
 222                        set_thread_flag(TIF_LOGADE);
 223                else
 224                        clear_thread_flag(TIF_LOGADE);
 225
 226                return 0;
 227
 228        case FLUSH_CACHE:
 229                __flush_cache_all();
 230                return 0;
 231        }
 232
 233        return -EINVAL;
 234}
 235
 236/*
 237 * No implemented yet ...
 238 */
 239SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
 240{
 241        return -ENOSYS;
 242}
 243
 244/*
 245 * If we ever come here the user sp is bad.  Zap the process right away.
 246 * Due to the bad stack signaling wouldn't work.
 247 */
 248asmlinkage void bad_stack(void)
 249{
 250        do_exit(SIGSEGV);
 251}
 252