linux/arch/arm26/kernel/sys_arm.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm26/kernel/sys_arm.c
   3 *
   4 *  Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c
   5 *  Copyright (C) 1995, 1996 Russell King.
   6 *  Copyright (C) 2003 Ian Molton.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 *  This file contains various random system calls that
  13 *  have a non-standard calling sequence on the Linux/arm
  14 *  platform.
  15 */
  16#include <linux/module.h>
  17#include <linux/errno.h>
  18#include <linux/sched.h>
  19#include <linux/slab.h>
  20#include <linux/mm.h>
  21#include <linux/sem.h>
  22#include <linux/msg.h>
  23#include <linux/shm.h>
  24#include <linux/stat.h>
  25#include <linux/syscalls.h>
  26#include <linux/mman.h>
  27#include <linux/fs.h>
  28#include <linux/file.h>
  29#include <linux/utsname.h>
  30
  31#include <asm/uaccess.h>
  32#include <asm/ipc.h>
  33
  34extern unsigned long do_mremap(unsigned long addr, unsigned long old_len,
  35                               unsigned long new_len, unsigned long flags,
  36                               unsigned long new_addr);
  37
  38/*
  39 * sys_pipe() is the normal C calling standard for creating
  40 * a pipe. It's not the way unix traditionally does this, though.
  41 */
  42asmlinkage int sys_pipe(unsigned long * fildes)
  43{
  44        int fd[2];
  45        int error;
  46
  47        error = do_pipe(fd);
  48        if (!error) {
  49                if (copy_to_user(fildes, fd, 2*sizeof(int)))
  50                        error = -EFAULT;
  51        }
  52        return error;
  53}
  54
  55/* common code for old and new mmaps */
  56inline long do_mmap2(
  57        unsigned long addr, unsigned long len,
  58        unsigned long prot, unsigned long flags,
  59        unsigned long fd, unsigned long pgoff)
  60{
  61        int error = -EINVAL;
  62        struct file * file = NULL;
  63
  64        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
  65
  66        /*
  67         * If we are doing a fixed mapping, and address < PAGE_SIZE,
  68         * then deny it.
  69         */
  70        if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0)
  71                goto out;
  72
  73        error = -EBADF;
  74        if (!(flags & MAP_ANONYMOUS)) {
  75                file = fget(fd);
  76                if (!file)
  77                        goto out;
  78        }
  79
  80        down_write(&current->mm->mmap_sem);
  81        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
  82        up_write(&current->mm->mmap_sem);
  83
  84        if (file)
  85                fput(file);
  86out:
  87        return error;
  88}
  89
  90struct mmap_arg_struct {
  91        unsigned long addr;
  92        unsigned long len;
  93        unsigned long prot;
  94        unsigned long flags;
  95        unsigned long fd;
  96        unsigned long offset;
  97};
  98
  99asmlinkage int old_mmap(struct mmap_arg_struct *arg)
 100{
 101        int error = -EFAULT;
 102        struct mmap_arg_struct a;
 103
 104        if (copy_from_user(&a, arg, sizeof(a)))
 105                goto out;
 106
 107        error = -EINVAL;
 108        if (a.offset & ~PAGE_MASK)
 109                goto out;
 110
 111        error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
 112out:
 113        return error;
 114}
 115
 116asmlinkage unsigned long
 117sys_arm_mremap(unsigned long addr, unsigned long old_len,
 118               unsigned long new_len, unsigned long flags,
 119               unsigned long new_addr)
 120{
 121        unsigned long ret = -EINVAL;
 122
 123        /*
 124         * If we are doing a fixed mapping, and address < PAGE_SIZE,
 125         * then deny it.
 126         */
 127        if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE &&
 128            vectors_base() == 0)
 129                goto out;
 130
 131        down_write(&current->mm->mmap_sem);
 132        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 133        up_write(&current->mm->mmap_sem);
 134
 135out:
 136        return ret;
 137}
 138
 139/*
 140 * Perform the select(nd, in, out, ex, tv) and mmap() system
 141 * calls.
 142 */
 143
 144struct sel_arg_struct {
 145        unsigned long n;
 146        fd_set *inp, *outp, *exp;
 147        struct timeval *tvp;
 148};
 149
 150asmlinkage int old_select(struct sel_arg_struct *arg)
 151{
 152        struct sel_arg_struct a;
 153
 154        if (copy_from_user(&a, arg, sizeof(a)))
 155                return -EFAULT;
 156        /* sys_select() does the appropriate kernel locking */
 157        return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 158}
 159
 160/*
 161 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
 162 *
 163 * This is really horribly ugly.
 164 */
 165asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 166{
 167        int version, ret;
 168
 169        version = call >> 16; /* hack for backward compatibility */
 170        call &= 0xffff;
 171
 172        switch (call) {
 173        case SEMOP:
 174                return sys_semop (first, (struct sembuf *)ptr, second);
 175        case SEMGET:
 176                return sys_semget (first, second, third);
 177        case SEMCTL: {
 178                union semun fourth;
 179                if (!ptr)
 180                        return -EINVAL;
 181                if (get_user(fourth.__pad, (void **) ptr))
 182                        return -EFAULT;
 183                return sys_semctl (first, second, third, fourth);
 184        }
 185
 186        case MSGSND:
 187                return sys_msgsnd (first, (struct msgbuf *) ptr, 
 188                                   second, third);
 189        case MSGRCV:
 190                switch (version) {
 191                case 0: {
 192                        struct ipc_kludge tmp;
 193                        if (!ptr)
 194                                return -EINVAL;
 195                        if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
 196                                           sizeof (tmp)))
 197                                return -EFAULT;
 198                        return sys_msgrcv (first, tmp.msgp, second,
 199                                           tmp.msgtyp, third);
 200                }
 201                default:
 202                        return sys_msgrcv (first,
 203                                           (struct msgbuf *) ptr,
 204                                           second, fifth, third);
 205                }
 206        case MSGGET:
 207                return sys_msgget ((key_t) first, second);
 208        case MSGCTL:
 209                return sys_msgctl (first, second, (struct msqid_ds *) ptr);
 210
 211        case SHMAT:
 212                switch (version) {
 213                default: {
 214                        ulong raddr;
 215                        ret = do_shmat (first, (char *) ptr, second, &raddr);
 216                        if (ret)
 217                                return ret;
 218                        return put_user (raddr, (ulong *) third);
 219                }
 220                case 1: /* iBCS2 emulator entry point */
 221                        if (!segment_eq(get_fs(), get_ds()))
 222                                return -EINVAL;
 223                        return do_shmat (first, (char *) ptr,
 224                                          second, (ulong *) third);
 225                }
 226        case SHMDT: 
 227                return sys_shmdt ((char *)ptr);
 228        case SHMGET:
 229                return sys_shmget (first, second, third);
 230        case SHMCTL:
 231                return sys_shmctl (first, second,
 232                                   (struct shmid_ds *) ptr);
 233        default:
 234                return -EINVAL;
 235        }
 236}
 237
 238/* Fork a new task - this creates a new program thread.
 239 * This is called indirectly via a small wrapper
 240 */
 241asmlinkage int sys_fork(struct pt_regs *regs)
 242{
 243        return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
 244}
 245
 246/* Clone a task - this clones the calling program thread.
 247 * This is called indirectly via a small wrapper
 248 */
 249asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
 250{
 251        /*
 252         * We don't support SETTID / CLEARTID  (FIXME!!! (nicked from arm32))
 253         */
 254        if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID))
 255                return -EINVAL;
 256        
 257        if (!newsp)
 258                newsp = regs->ARM_sp;
 259
 260        return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
 261}
 262
 263asmlinkage int sys_vfork(struct pt_regs *regs)
 264{
 265        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
 266}
 267
 268/* sys_execve() executes a new program.
 269 * This is called indirectly via a small wrapper
 270 */
 271asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, struct pt_regs *regs)
 272{
 273        int error;
 274        char * filename;
 275
 276        filename = getname(filenamei);
 277        error = PTR_ERR(filename);
 278        if (IS_ERR(filename))
 279                goto out;
 280        error = do_execve(filename, argv, envp, regs);
 281        putname(filename);
 282out:
 283        return error;
 284}
 285
 286/* FIXME - see if this is correct for arm26 */
 287long execve(const char *filename, char **argv, char **envp)
 288{
 289        struct pt_regs regs;
 290        int ret;
 291         memset(&regs, 0, sizeof(struct pt_regs));
 292        ret = do_execve((char *)filename, (char __user * __user *)argv,                         (char __user * __user *)envp, &regs);
 293        if (ret < 0)
 294                goto out;
 295
 296        /*
 297         * Save argc to the register structure for userspace.
 298         */
 299        regs.ARM_r0 = ret;
 300
 301        /*
 302         * We were successful.  We won't be returning to our caller, but
 303         * instead to user space by manipulating the kernel stack.
 304         */
 305        asm(    "add    r0, %0, %1\n\t"
 306                "mov    r1, %2\n\t"
 307                "mov    r2, %3\n\t"
 308                "bl     memmove\n\t"    /* copy regs to top of stack */
 309                "mov    r8, #0\n\t"     /* not a syscall */
 310                "mov    r9, %0\n\t"     /* thread structure */
 311                "mov    sp, r0\n\t"     /* reposition stack pointer */
 312                "b      ret_to_user"
 313                :
 314                : "r" (current_thread_info()),
 315                  "Ir" (THREAD_SIZE - 8 - sizeof(regs)),
 316                  "r" (&regs),
 317                  "Ir" (sizeof(regs))
 318                : "r0", "r1", "r2", "r3", "ip", "memory");
 319
 320 out:
 321        return ret;
 322}
 323
 324EXPORT_SYMBOL(execve);
 325
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.