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/mm.h>
  14#include <linux/fs.h>
  15#include <linux/smp.h>
  16#include <linux/mman.h>
  17#include <linux/ptrace.h>
  18#include <linux/sched.h>
  19#include <linux/string.h>
  20#include <linux/syscalls.h>
  21#include <linux/file.h>
  22#include <linux/slab.h>
  23#include <linux/utsname.h>
  24#include <linux/unistd.h>
  25#include <linux/sem.h>
  26#include <linux/msg.h>
  27#include <linux/shm.h>
  28#include <linux/compiler.h>
  29#include <linux/module.h>
  30#include <linux/ipc.h>
  31#include <linux/uaccess.h>
  32
  33#include <asm/asm.h>
  34#include <asm/branch.h>
  35#include <asm/cachectl.h>
  36#include <asm/cacheflush.h>
  37#include <asm/asm-offsets.h>
  38#include <asm/signal.h>
  39#include <asm/sim.h>
  40#include <asm/shmparam.h>
  41#include <asm/sysmips.h>
  42#include <asm/uaccess.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(nabi_no_regargs volatile struct pt_regs regs)
  52{
  53        int fd[2];
  54        int error, res;
  55
  56        error = do_pipe_flags(fd, 0);
  57        if (error) {
  58                res = error;
  59                goto out;
  60        }
  61        regs.regs[3] = fd[1];
  62        res = fd[0];
  63out:
  64        return res;
  65}
  66
  67unsigned long shm_align_mask = PAGE_SIZE - 1;   /* Sane caches */
  68
  69EXPORT_SYMBOL(shm_align_mask);
  70
  71#define COLOUR_ALIGN(addr,pgoff)                                \
  72        ((((addr) + shm_align_mask) & ~shm_align_mask) +        \
  73         (((pgoff) << PAGE_SHIFT) & shm_align_mask))
  74
  75unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
  76        unsigned long len, unsigned long pgoff, unsigned long flags)
  77{
  78        struct vm_area_struct * vmm;
  79        int do_color_align;
  80        unsigned long task_size;
  81
  82        task_size = STACK_TOP;
  83
  84        if (len > task_size)
  85                return -ENOMEM;
  86
  87        if (flags & MAP_FIXED) {
  88                /* Even MAP_FIXED mappings must reside within task_size.  */
  89                if (task_size - len < addr)
  90                        return -EINVAL;
  91
  92                /*
  93                 * We do not accept a shared mapping if it would violate
  94                 * cache aliasing constraints.
  95                 */
  96                if ((flags & MAP_SHARED) && (addr & shm_align_mask))
  97                        return -EINVAL;
  98                return addr;
  99        }
 100
 101        do_color_align = 0;
 102        if (filp || (flags & MAP_SHARED))
 103                do_color_align = 1;
 104        if (addr) {
 105                if (do_color_align)
 106                        addr = COLOUR_ALIGN(addr, pgoff);
 107                else
 108                        addr = PAGE_ALIGN(addr);
 109                vmm = find_vma(current->mm, addr);
 110                if (task_size - len >= addr &&
 111                    (!vmm || addr + len <= vmm->vm_start))
 112                        return addr;
 113        }
 114        addr = TASK_UNMAPPED_BASE;
 115        if (do_color_align)
 116                addr = COLOUR_ALIGN(addr, pgoff);
 117        else
 118                addr = PAGE_ALIGN(addr);
 119
 120        for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
 121                /* At this point:  (!vmm || addr < vmm->vm_end). */
 122                if (task_size - len < addr)
 123                        return -ENOMEM;
 124                if (!vmm || addr + len <= vmm->vm_start)
 125                        return addr;
 126                addr = vmm->vm_end;
 127                if (do_color_align)
 128                        addr = COLOUR_ALIGN(addr, pgoff);
 129        }
 130}
 131
 132/* common code for old and new mmaps */
 133static inline unsigned long
 134do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
 135        unsigned long flags, unsigned long fd, unsigned long pgoff)
 136{
 137        unsigned long error = -EBADF;
 138        struct file * file = NULL;
 139
 140        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 141        if (!(flags & MAP_ANONYMOUS)) {
 142                file = fget(fd);
 143                if (!file)
 144                        goto out;
 145        }
 146
 147        down_write(&current->mm->mmap_sem);
 148        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 149        up_write(&current->mm->mmap_sem);
 150
 151        if (file)
 152                fput(file);
 153out:
 154        return error;
 155}
 156
 157SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
 158        unsigned long, prot, unsigned long, flags, unsigned long,
 159        fd, off_t, offset)
 160{
 161        unsigned long result;
 162
 163        result = -EINVAL;
 164        if (offset & ~PAGE_MASK)
 165                goto out;
 166
 167        result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
 168
 169out:
 170        return result;
 171}
 172
 173SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
 174        unsigned long, prot, unsigned long, flags, unsigned long, fd,
 175        unsigned long, pgoff)
 176{
 177        if (pgoff & (~PAGE_MASK >> 12))
 178                return -EINVAL;
 179
 180        return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
 181}
 182
 183save_static_function(sys_fork);
 184static int __used noinline
 185_sys_fork(nabi_no_regargs struct pt_regs regs)
 186{
 187        return do_fork(SIGCHLD, regs.regs[29], &regs, 0, NULL, NULL);
 188}
 189
 190save_static_function(sys_clone);
 191static int __used noinline
 192_sys_clone(nabi_no_regargs struct pt_regs regs)
 193{
 194        unsigned long clone_flags;
 195        unsigned long newsp;
 196        int __user *parent_tidptr, *child_tidptr;
 197
 198        clone_flags = regs.regs[4];
 199        newsp = regs.regs[5];
 200        if (!newsp)
 201                newsp = regs.regs[29];
 202        parent_tidptr = (int __user *) regs.regs[6];
 203#ifdef CONFIG_32BIT
 204        /* We need to fetch the fifth argument off the stack.  */
 205        child_tidptr = NULL;
 206        if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
 207                int __user *__user *usp = (int __user *__user *) regs.regs[29];
 208                if (regs.regs[2] == __NR_syscall) {
 209                        if (get_user (child_tidptr, &usp[5]))
 210                                return -EFAULT;
 211                }
 212                else if (get_user (child_tidptr, &usp[4]))
 213                        return -EFAULT;
 214        }
 215#else
 216        child_tidptr = (int __user *) regs.regs[8];
 217#endif
 218        return do_fork(clone_flags, newsp, &regs, 0,
 219                       parent_tidptr, child_tidptr);
 220}
 221
 222/*
 223 * sys_execve() executes a new program.
 224 */
 225asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
 226{
 227        int error;
 228        char * filename;
 229
 230        filename = getname((char __user *) (long)regs.regs[4]);
 231        error = PTR_ERR(filename);
 232        if (IS_ERR(filename))
 233                goto out;
 234        error = do_execve(filename, (char __user *__user *) (long)regs.regs[5],
 235                          (char __user *__user *) (long)regs.regs[6], &regs);
 236        putname(filename);
 237
 238out:
 239        return error;
 240}
 241
 242/*
 243 * Compacrapability ...
 244 */
 245SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
 246{
 247        if (name && !copy_to_user(name, utsname(), sizeof (*name)))
 248                return 0;
 249        return -EFAULT;
 250}
 251
 252/*
 253 * Compacrapability ...
 254 */
 255SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
 256{
 257        int error;
 258
 259        if (!name)
 260                return -EFAULT;
 261        if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
 262                return -EFAULT;
 263
 264        error = __copy_to_user(&name->sysname, &utsname()->sysname,
 265                               __OLD_UTS_LEN);
 266        error -= __put_user(0, name->sysname + __OLD_UTS_LEN);
 267        error -= __copy_to_user(&name->nodename, &utsname()->nodename,
 268                                __OLD_UTS_LEN);
 269        error -= __put_user(0, name->nodename + __OLD_UTS_LEN);
 270        error -= __copy_to_user(&name->release, &utsname()->release,
 271                                __OLD_UTS_LEN);
 272        error -= __put_user(0, name->release + __OLD_UTS_LEN);
 273        error -= __copy_to_user(&name->version, &utsname()->version,
 274                                __OLD_UTS_LEN);
 275        error -= __put_user(0, name->version + __OLD_UTS_LEN);
 276        error -= __copy_to_user(&name->machine, &utsname()->machine,
 277                                __OLD_UTS_LEN);
 278        error = __put_user(0, name->machine + __OLD_UTS_LEN);
 279        error = error ? -EFAULT : 0;
 280
 281        return error;
 282}
 283
 284SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
 285{
 286        struct thread_info *ti = task_thread_info(current);
 287
 288        ti->tp_value = addr;
 289        if (cpu_has_userlocal)
 290                write_c0_userlocal(addr);
 291
 292        return 0;
 293}
 294
 295static inline int mips_atomic_set(struct pt_regs *regs,
 296        unsigned long addr, unsigned long new)
 297{
 298        unsigned long old, tmp;
 299        unsigned int err;
 300
 301        if (unlikely(addr & 3))
 302                return -EINVAL;
 303
 304        if (unlikely(!access_ok(VERIFY_WRITE, addr, 4)))
 305                return -EINVAL;
 306
 307        if (cpu_has_llsc && R10000_LLSC_WAR) {
 308                __asm__ __volatile__ (
 309                "       .set    mips3                                   \n"
 310                "       li      %[err], 0                               \n"
 311                "1:     ll      %[old], (%[addr])                       \n"
 312                "       move    %[tmp], %[new]                          \n"
 313                "2:     sc      %[tmp], (%[addr])                       \n"
 314                "       beqzl   %[tmp], 1b                              \n"
 315                "3:                                                     \n"
 316                "       .section .fixup,\"ax\"                          \n"
 317                "4:     li      %[err], %[efault]                       \n"
 318                "       j       3b                                      \n"
 319                "       .previous                                       \n"
 320                "       .section __ex_table,\"a\"                       \n"
 321                "       "STR(PTR)"      1b, 4b                          \n"
 322                "       "STR(PTR)"      2b, 4b                          \n"
 323                "       .previous                                       \n"
 324                "       .set    mips0                                   \n"
 325                : [old] "=&r" (old),
 326                  [err] "=&r" (err),
 327                  [tmp] "=&r" (tmp)
 328                : [addr] "r" (addr),
 329                  [new] "r" (new),
 330                  [efault] "i" (-EFAULT)
 331                : "memory");
 332        } else if (cpu_has_llsc) {
 333                __asm__ __volatile__ (
 334                "       .set    mips3                                   \n"
 335                "       li      %[err], 0                               \n"
 336                "1:     ll      %[old], (%[addr])                       \n"
 337                "       move    %[tmp], %[new]                          \n"
 338                "2:     sc      %[tmp], (%[addr])                       \n"
 339                "       bnez    %[tmp], 4f                              \n"
 340                "3:                                                     \n"
 341                "       .subsection 2                                   \n"
 342                "4:     b       1b                                      \n"
 343                "       .previous                                       \n"
 344                "                                                       \n"
 345                "       .section .fixup,\"ax\"                          \n"
 346                "5:     li      %[err], %[efault]                       \n"
 347                "       j       3b                                      \n"
 348                "       .previous                                       \n"
 349                "       .section __ex_table,\"a\"                       \n"
 350                "       "STR(PTR)"      1b, 5b                          \n"
 351                "       "STR(PTR)"      2b, 5b                          \n"
 352                "       .previous                                       \n"
 353                "       .set    mips0                                   \n"
 354                : [old] "=&r" (old),
 355                  [err] "=&r" (err),
 356                  [tmp] "=&r" (tmp)
 357                : [addr] "r" (addr),
 358                  [new] "r" (new),
 359                  [efault] "i" (-EFAULT)
 360                : "memory");
 361        } else {
 362                do {
 363                        preempt_disable();
 364                        ll_bit = 1;
 365                        ll_task = current;
 366                        preempt_enable();
 367
 368                        err = __get_user(old, (unsigned int *) addr);
 369                        err |= __put_user(new, (unsigned int *) addr);
 370                        if (err)
 371                                break;
 372                        rmb();
 373                } while (!ll_bit);
 374        }
 375
 376        if (unlikely(err))
 377                return err;
 378
 379        regs->regs[2] = old;
 380        regs->regs[7] = 0;      /* No error */
 381
 382        /*
 383         * Don't let your children do this ...
 384         */
 385        __asm__ __volatile__(
 386        "       move    $29, %0                                         \n"
 387        "       j       syscall_exit                                    \n"
 388        : /* no outputs */
 389        : "r" (regs));
 390
 391        /* unreached.  Honestly.  */
 392        while (1);
 393}
 394
 395save_static_function(sys_sysmips);
 396static int __used noinline
 397_sys_sysmips(nabi_no_regargs struct pt_regs regs)
 398{
 399        long cmd, arg1, arg2, arg3;
 400
 401        cmd = regs.regs[4];
 402        arg1 = regs.regs[5];
 403        arg2 = regs.regs[6];
 404        arg3 = regs.regs[7];
 405
 406        switch (cmd) {
 407        case MIPS_ATOMIC_SET:
 408                return mips_atomic_set(&regs, arg1, arg2);
 409
 410        case MIPS_FIXADE:
 411                if (arg1 & ~3)
 412                        return -EINVAL;
 413
 414                if (arg1 & 1)
 415                        set_thread_flag(TIF_FIXADE);
 416                else
 417                        clear_thread_flag(TIF_FIXADE);
 418                if (arg1 & 2)
 419                        set_thread_flag(TIF_LOGADE);
 420                else
 421                        clear_thread_flag(TIF_FIXADE);
 422
 423                return 0;
 424
 425        case FLUSH_CACHE:
 426                __flush_cache_all();
 427                return 0;
 428        }
 429
 430        return -EINVAL;
 431}
 432
 433/*
 434 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
 435 *
 436 * This is really horribly ugly.
 437 */
 438SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second,
 439        unsigned long, third, void __user *, ptr, long, fifth)
 440{
 441        int version, ret;
 442
 443        version = call >> 16; /* hack for backward compatibility */
 444        call &= 0xffff;
 445
 446        switch (call) {
 447        case SEMOP:
 448                return sys_semtimedop(first, (struct sembuf __user *)ptr,
 449                                      second, NULL);
 450        case SEMTIMEDOP:
 451                return sys_semtimedop(first, (struct sembuf __user *)ptr,
 452                                      second,
 453                                      (const struct timespec __user *)fifth);
 454        case SEMGET:
 455                return sys_semget(first, second, third);
 456        case SEMCTL: {
 457                union semun fourth;
 458                if (!ptr)
 459                        return -EINVAL;
 460                if (get_user(fourth.__pad, (void __user *__user *) ptr))
 461                        return -EFAULT;
 462                return sys_semctl(first, second, third, fourth);
 463        }
 464
 465        case MSGSND:
 466                return sys_msgsnd(first, (struct msgbuf __user *) ptr,
 467                                  second, third);
 468        case MSGRCV:
 469                switch (version) {
 470                case 0: {
 471                        struct ipc_kludge tmp;
 472                        if (!ptr)
 473                                return -EINVAL;
 474
 475                        if (copy_from_user(&tmp,
 476                                           (struct ipc_kludge __user *) ptr,
 477                                           sizeof(tmp)))
 478                                return -EFAULT;
 479                        return sys_msgrcv(first, tmp.msgp, second,
 480                                          tmp.msgtyp, third);
 481                }
 482                default:
 483                        return sys_msgrcv(first,
 484                                          (struct msgbuf __user *) ptr,
 485                                          second, fifth, third);
 486                }
 487        case MSGGET:
 488                return sys_msgget((key_t) first, second);
 489        case MSGCTL:
 490                return sys_msgctl(first, second,
 491                                  (struct msqid_ds __user *) ptr);
 492
 493        case SHMAT:
 494                switch (version) {
 495                default: {
 496                        unsigned long raddr;
 497                        ret = do_shmat(first, (char __user *) ptr, second,
 498                                       &raddr);
 499                        if (ret)
 500                                return ret;
 501                        return put_user(raddr, (unsigned long __user *) third);
 502                }
 503                case 1: /* iBCS2 emulator entry point */
 504                        if (!segment_eq(get_fs(), get_ds()))
 505                                return -EINVAL;
 506                        return do_shmat(first, (char __user *) ptr, second,
 507                                        (unsigned long *) third);
 508                }
 509        case SHMDT:
 510                return sys_shmdt((char __user *)ptr);
 511        case SHMGET:
 512                return sys_shmget(first, second, third);
 513        case SHMCTL:
 514                return sys_shmctl(first, second,
 515                                  (struct shmid_ds __user *) ptr);
 516        default:
 517                return -ENOSYS;
 518        }
 519}
 520
 521/*
 522 * No implemented yet ...
 523 */
 524SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
 525{
 526        return -ENOSYS;
 527}
 528
 529/*
 530 * If we ever come here the user sp is bad.  Zap the process right away.
 531 * Due to the bad stack signaling wouldn't work.
 532 */
 533asmlinkage void bad_stack(void)
 534{
 535        do_exit(SIGSEGV);
 536}
 537
 538/*
 539 * Do a system call from kernel instead of calling sys_execve so we
 540 * end up with proper pt_regs.
 541 */
 542int kernel_execve(const char *filename, char *const argv[], char *const envp[])
 543{
 544        register unsigned long __a0 asm("$4") = (unsigned long) filename;
 545        register unsigned long __a1 asm("$5") = (unsigned long) argv;
 546        register unsigned long __a2 asm("$6") = (unsigned long) envp;
 547        register unsigned long __a3 asm("$7");
 548        unsigned long __v0;
 549
 550        __asm__ volatile ("                                     \n"
 551        "       .set    noreorder                               \n"
 552        "       li      $2, %5          # __NR_execve           \n"
 553        "       syscall                                         \n"
 554        "       move    %0, $2                                  \n"
 555        "       .set    reorder                                 \n"
 556        : "=&r" (__v0), "=r" (__a3)
 557        : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
 558        : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
 559          "memory");
 560
 561        if (__a3 == 0)
 562                return __v0;
 563
 564        return -__v0;
 565}
 566