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/sysmips.h>
  41#include <asm/switch_to.h>
  42
  43/*
  44 * For historic reasons the pipe(2) syscall on MIPS has an unusual calling
  45 * convention.  It returns results in registers $v0 / $v1 which means there
  46 * is no need for it to do verify the validity of a userspace pointer
  47 * argument.  Historically that used to be expensive in Linux.  These days
  48 * the performance advantage is negligible.
  49 */
  50asmlinkage int sysm_pipe(void)
  51{
  52        int fd[2];
  53        int error = do_pipe_flags(fd, 0);
  54        if (error)
  55                return error;
  56        current_pt_regs()->regs[3] = fd[1];
  57        return fd[0];
  58}
  59
  60SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
  61        unsigned long, prot, unsigned long, flags, unsigned long,
  62        fd, off_t, offset)
  63{
  64        if (offset & ~PAGE_MASK)
  65                return -EINVAL;
  66        return ksys_mmap_pgoff(addr, len, prot, flags, fd,
  67                               offset >> PAGE_SHIFT);
  68}
  69
  70SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
  71        unsigned long, prot, unsigned long, flags, unsigned long, fd,
  72        unsigned long, pgoff)
  73{
  74        if (pgoff & (~PAGE_MASK >> 12))
  75                return -EINVAL;
  76
  77        return ksys_mmap_pgoff(addr, len, prot, flags, fd,
  78                               pgoff >> (PAGE_SHIFT - 12));
  79}
  80
  81save_static_function(sys_fork);
  82save_static_function(sys_clone);
  83
  84SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
  85{
  86        struct thread_info *ti = task_thread_info(current);
  87
  88        ti->tp_value = addr;
  89        if (cpu_has_userlocal)
  90                write_c0_userlocal(addr);
  91
  92        return 0;
  93}
  94
  95static inline int mips_atomic_set(unsigned long addr, unsigned long new)
  96{
  97        unsigned long old, tmp;
  98        struct pt_regs *regs;
  99        unsigned int err;
 100
 101        if (unlikely(addr & 3))
 102                return -EINVAL;
 103
 104        if (unlikely(!access_ok(VERIFY_WRITE, (const void __user *)addr, 4)))
 105                return -EINVAL;
 106
 107        if (cpu_has_llsc && R10000_LLSC_WAR) {
 108                __asm__ __volatile__ (
 109                "       .set    arch=r4000                              \n"
 110                "       li      %[err], 0                               \n"
 111                "1:     ll      %[old], (%[addr])                       \n"
 112                "       move    %[tmp], %[new]                          \n"
 113                "2:     sc      %[tmp], (%[addr])                       \n"
 114                "       beqzl   %[tmp], 1b                              \n"
 115                "3:                                                     \n"
 116                "       .insn                                           \n"
 117                "       .section .fixup,\"ax\"                          \n"
 118                "4:     li      %[err], %[efault]                       \n"
 119                "       j       3b                                      \n"
 120                "       .previous                                       \n"
 121                "       .section __ex_table,\"a\"                       \n"
 122                "       "STR(PTR)"      1b, 4b                          \n"
 123                "       "STR(PTR)"      2b, 4b                          \n"
 124                "       .previous                                       \n"
 125                "       .set    mips0                                   \n"
 126                : [old] "=&r" (old),
 127                  [err] "=&r" (err),
 128                  [tmp] "=&r" (tmp)
 129                : [addr] "r" (addr),
 130                  [new] "r" (new),
 131                  [efault] "i" (-EFAULT)
 132                : "memory");
 133        } else if (cpu_has_llsc) {
 134                __asm__ __volatile__ (
 135                "       .set    "MIPS_ISA_ARCH_LEVEL"                   \n"
 136                "       li      %[err], 0                               \n"
 137                "1:                                                     \n"
 138                user_ll("%[old]", "(%[addr])")
 139                "       move    %[tmp], %[new]                          \n"
 140                "2:                                                     \n"
 141                user_sc("%[tmp]", "(%[addr])")
 142                "       beqz    %[tmp], 1b                              \n"
 143                "3:                                                     \n"
 144                "       .insn                                           \n"
 145                "       .section .fixup,\"ax\"                          \n"
 146                "5:     li      %[err], %[efault]                       \n"
 147                "       j       3b                                      \n"
 148                "       .previous                                       \n"
 149                "       .section __ex_table,\"a\"                       \n"
 150                "       "STR(PTR)"      1b, 5b                          \n"
 151                "       "STR(PTR)"      2b, 5b                          \n"
 152                "       .previous                                       \n"
 153                "       .set    mips0                                   \n"
 154                : [old] "=&r" (old),
 155                  [err] "=&r" (err),
 156                  [tmp] "=&r" (tmp)
 157                : [addr] "r" (addr),
 158                  [new] "r" (new),
 159                  [efault] "i" (-EFAULT)
 160                : "memory");
 161        } else {
 162                do {
 163                        preempt_disable();
 164                        ll_bit = 1;
 165                        ll_task = current;
 166                        preempt_enable();
 167
 168                        err = __get_user(old, (unsigned int *) addr);
 169                        err |= __put_user(new, (unsigned int *) addr);
 170                        if (err)
 171                                break;
 172                        rmb();
 173                } while (!ll_bit);
 174        }
 175
 176        if (unlikely(err))
 177                return err;
 178
 179        regs = current_pt_regs();
 180        regs->regs[2] = old;
 181        regs->regs[7] = 0;      /* No error */
 182
 183        /*
 184         * Don't let your children do this ...
 185         */
 186        __asm__ __volatile__(
 187        "       move    $29, %0                                         \n"
 188        "       j       syscall_exit                                    \n"
 189        : /* no outputs */
 190        : "r" (regs));
 191
 192        /* unreached.  Honestly.  */
 193        unreachable();
 194}
 195
 196/*
 197 * mips_atomic_set() normally returns directly via syscall_exit potentially
 198 * clobbering static registers, so be sure to preserve them.
 199 */
 200save_static_function(sys_sysmips);
 201
 202SYSCALL_DEFINE3(sysmips, long, cmd, long, arg1, long, arg2)
 203{
 204        switch (cmd) {
 205        case MIPS_ATOMIC_SET:
 206                return mips_atomic_set(arg1, arg2);
 207
 208        case MIPS_FIXADE:
 209                if (arg1 & ~3)
 210                        return -EINVAL;
 211
 212                if (arg1 & 1)
 213                        set_thread_flag(TIF_FIXADE);
 214                else
 215                        clear_thread_flag(TIF_FIXADE);
 216                if (arg1 & 2)
 217                        set_thread_flag(TIF_LOGADE);
 218                else
 219                        clear_thread_flag(TIF_LOGADE);
 220
 221                return 0;
 222
 223        case FLUSH_CACHE:
 224                __flush_cache_all();
 225                return 0;
 226        }
 227
 228        return -EINVAL;
 229}
 230
 231/*
 232 * No implemented yet ...
 233 */
 234SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
 235{
 236        return -ENOSYS;
 237}
 238
 239/*
 240 * If we ever come here the user sp is bad.  Zap the process right away.
 241 * Due to the bad stack signaling wouldn't work.
 242 */
 243asmlinkage void bad_stack(void)
 244{
 245        do_exit(SIGSEGV);
 246}
 247