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