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