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
  30#include <asm/asm.h>
  31#include <asm/branch.h>
  32#include <asm/cachectl.h>
  33#include <asm/cacheflush.h>
  34#include <asm/asm-offsets.h>
  35#include <asm/signal.h>
  36#include <asm/sim.h>
  37#include <asm/shmparam.h>
  38#include <asm/sysmips.h>
  39#include <asm/uaccess.h>
  40
  41/*
  42 * For historic reasons the pipe(2) syscall on MIPS has an unusual calling
  43 * convention.  It returns results in registers $v0 / $v1 which means there
  44 * is no need for it to do verify the validity of a userspace pointer
  45 * argument.  Historically that used to be expensive in Linux.  These days
  46 * the performance advantage is negligible.
  47 */
  48asmlinkage int sysm_pipe(nabi_no_regargs volatile struct pt_regs regs)
  49{
  50        int fd[2];
  51        int error, res;
  52
  53        error = do_pipe_flags(fd, 0);
  54        if (error) {
  55                res = error;
  56                goto out;
  57        }
  58        regs.regs[3] = fd[1];
  59        res = fd[0];
  60out:
  61        return res;
  62}
  63
  64SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
  65        unsigned long, prot, unsigned long, flags, unsigned long,
  66        fd, off_t, offset)
  67{
  68        unsigned long result;
  69
  70        result = -EINVAL;
  71        if (offset & ~PAGE_MASK)
  72                goto out;
  73
  74        result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
  75
  76out:
  77        return result;
  78}
  79
  80SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
  81        unsigned long, prot, unsigned long, flags, unsigned long, fd,
  82        unsigned long, pgoff)
  83{
  84        if (pgoff & (~PAGE_MASK >> 12))
  85                return -EINVAL;
  86
  87        return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
  88}
  89
  90save_static_function(sys_fork);
  91static int __used noinline
  92_sys_fork(nabi_no_regargs struct pt_regs regs)
  93{
  94        return do_fork(SIGCHLD, regs.regs[29], &regs, 0, NULL, NULL);
  95}
  96
  97save_static_function(sys_clone);
  98static int __used noinline
  99_sys_clone(nabi_no_regargs struct pt_regs regs)
 100{
 101        unsigned long clone_flags;
 102        unsigned long newsp;
 103        int __user *parent_tidptr, *child_tidptr;
 104
 105        clone_flags = regs.regs[4];
 106        newsp = regs.regs[5];
 107        if (!newsp)
 108                newsp = regs.regs[29];
 109        parent_tidptr = (int __user *) regs.regs[6];
 110#ifdef CONFIG_32BIT
 111        /* We need to fetch the fifth argument off the stack.  */
 112        child_tidptr = NULL;
 113        if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
 114                int __user *__user *usp = (int __user *__user *) regs.regs[29];
 115                if (regs.regs[2] == __NR_syscall) {
 116                        if (get_user (child_tidptr, &usp[5]))
 117                                return -EFAULT;
 118                }
 119                else if (get_user (child_tidptr, &usp[4]))
 120                        return -EFAULT;
 121        }
 122#else
 123        child_tidptr = (int __user *) regs.regs[8];
 124#endif
 125        return do_fork(clone_flags, newsp, &regs, 0,
 126                       parent_tidptr, child_tidptr);
 127}
 128
 129/*
 130 * sys_execve() executes a new program.
 131 */
 132asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
 133{
 134        int error;
 135        char * filename;
 136
 137        filename = getname((const char __user *) (long)regs.regs[4]);
 138        error = PTR_ERR(filename);
 139        if (IS_ERR(filename))
 140                goto out;
 141        error = do_execve(filename,
 142                          (const char __user *const __user *) (long)regs.regs[5],
 143                          (const char __user *const __user *) (long)regs.regs[6],
 144                          &regs);
 145        putname(filename);
 146
 147out:
 148        return error;
 149}
 150
 151SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
 152{
 153        struct thread_info *ti = task_thread_info(current);
 154
 155        ti->tp_value = addr;
 156        if (cpu_has_userlocal)
 157                write_c0_userlocal(addr);
 158
 159        return 0;
 160}
 161
 162static inline int mips_atomic_set(struct pt_regs *regs,
 163        unsigned long addr, unsigned long new)
 164{
 165        unsigned long old, tmp;
 166        unsigned int err;
 167
 168        if (unlikely(addr & 3))
 169                return -EINVAL;
 170
 171        if (unlikely(!access_ok(VERIFY_WRITE, addr, 4)))
 172                return -EINVAL;
 173
 174        if (cpu_has_llsc && R10000_LLSC_WAR) {
 175                __asm__ __volatile__ (
 176                "       .set    mips3                                   \n"
 177                "       li      %[err], 0                               \n"
 178                "1:     ll      %[old], (%[addr])                       \n"
 179                "       move    %[tmp], %[new]                          \n"
 180                "2:     sc      %[tmp], (%[addr])                       \n"
 181                "       beqzl   %[tmp], 1b                              \n"
 182                "3:                                                     \n"
 183                "       .section .fixup,\"ax\"                          \n"
 184                "4:     li      %[err], %[efault]                       \n"
 185                "       j       3b                                      \n"
 186                "       .previous                                       \n"
 187                "       .section __ex_table,\"a\"                       \n"
 188                "       "STR(PTR)"      1b, 4b                          \n"
 189                "       "STR(PTR)"      2b, 4b                          \n"
 190                "       .previous                                       \n"
 191                "       .set    mips0                                   \n"
 192                : [old] "=&r" (old),
 193                  [err] "=&r" (err),
 194                  [tmp] "=&r" (tmp)
 195                : [addr] "r" (addr),
 196                  [new] "r" (new),
 197                  [efault] "i" (-EFAULT)
 198                : "memory");
 199        } else if (cpu_has_llsc) {
 200                __asm__ __volatile__ (
 201                "       .set    mips3                                   \n"
 202                "       li      %[err], 0                               \n"
 203                "1:     ll      %[old], (%[addr])                       \n"
 204                "       move    %[tmp], %[new]                          \n"
 205                "2:     sc      %[tmp], (%[addr])                       \n"
 206                "       bnez    %[tmp], 4f                              \n"
 207                "3:                                                     \n"
 208                "       .subsection 2                                   \n"
 209                "4:     b       1b                                      \n"
 210                "       .previous                                       \n"
 211                "                                                       \n"
 212                "       .section .fixup,\"ax\"                          \n"
 213                "5:     li      %[err], %[efault]                       \n"
 214                "       j       3b                                      \n"
 215                "       .previous                                       \n"
 216                "       .section __ex_table,\"a\"                       \n"
 217                "       "STR(PTR)"      1b, 5b                          \n"
 218                "       "STR(PTR)"      2b, 5b                          \n"
 219                "       .previous                                       \n"
 220                "       .set    mips0                                   \n"
 221                : [old] "=&r" (old),
 222                  [err] "=&r" (err),
 223                  [tmp] "=&r" (tmp)
 224                : [addr] "r" (addr),
 225                  [new] "r" (new),
 226                  [efault] "i" (-EFAULT)
 227                : "memory");
 228        } else {
 229                do {
 230                        preempt_disable();
 231                        ll_bit = 1;
 232                        ll_task = current;
 233                        preempt_enable();
 234
 235                        err = __get_user(old, (unsigned int *) addr);
 236                        err |= __put_user(new, (unsigned int *) addr);
 237                        if (err)
 238                                break;
 239                        rmb();
 240                } while (!ll_bit);
 241        }
 242
 243        if (unlikely(err))
 244                return err;
 245
 246        regs->regs[2] = old;
 247        regs->regs[7] = 0;      /* No error */
 248
 249        /*
 250         * Don't let your children do this ...
 251         */
 252        __asm__ __volatile__(
 253        "       move    $29, %0                                         \n"
 254        "       j       syscall_exit                                    \n"
 255        : /* no outputs */
 256        : "r" (regs));
 257
 258        /* unreached.  Honestly.  */
 259        while (1);
 260}
 261
 262save_static_function(sys_sysmips);
 263static int __used noinline
 264_sys_sysmips(nabi_no_regargs struct pt_regs regs)
 265{
 266        long cmd, arg1, arg2;
 267
 268        cmd = regs.regs[4];
 269        arg1 = regs.regs[5];
 270        arg2 = regs.regs[6];
 271
 272        switch (cmd) {
 273        case MIPS_ATOMIC_SET:
 274                return mips_atomic_set(&regs, arg1, arg2);
 275
 276        case MIPS_FIXADE:
 277                if (arg1 & ~3)
 278                        return -EINVAL;
 279
 280                if (arg1 & 1)
 281                        set_thread_flag(TIF_FIXADE);
 282                else
 283                        clear_thread_flag(TIF_FIXADE);
 284                if (arg1 & 2)
 285                        set_thread_flag(TIF_LOGADE);
 286                else
 287                        clear_thread_flag(TIF_LOGADE);
 288
 289                return 0;
 290
 291        case FLUSH_CACHE:
 292                __flush_cache_all();
 293                return 0;
 294        }
 295
 296        return -EINVAL;
 297}
 298
 299/*
 300 * No implemented yet ...
 301 */
 302SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
 303{
 304        return -ENOSYS;
 305}
 306
 307/*
 308 * If we ever come here the user sp is bad.  Zap the process right away.
 309 * Due to the bad stack signaling wouldn't work.
 310 */
 311asmlinkage void bad_stack(void)
 312{
 313        do_exit(SIGSEGV);
 314}
 315
 316/*
 317 * Do a system call from kernel instead of calling sys_execve so we
 318 * end up with proper pt_regs.
 319 */
 320int kernel_execve(const char *filename,
 321                  const char *const argv[],
 322                  const char *const envp[])
 323{
 324        register unsigned long __a0 asm("$4") = (unsigned long) filename;
 325        register unsigned long __a1 asm("$5") = (unsigned long) argv;
 326        register unsigned long __a2 asm("$6") = (unsigned long) envp;
 327        register unsigned long __a3 asm("$7");
 328        unsigned long __v0;
 329
 330        __asm__ volatile ("                                     \n"
 331        "       .set    noreorder                               \n"
 332        "       li      $2, %5          # __NR_execve           \n"
 333        "       syscall                                         \n"
 334        "       move    %0, $2                                  \n"
 335        "       .set    reorder                                 \n"
 336        : "=&r" (__v0), "=r" (__a3)
 337        : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
 338        : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
 339          "memory");
 340
 341        if (__a3 == 0)
 342                return __v0;
 343
 344        return -__v0;
 345}
 346