linux-old/arch/ppc/kernel/syscalls.c
<<
>>
Prefs
   1/*
   2 * linux/arch/ppc/kernel/sys_ppc.c
   3 *
   4 *  PowerPC version
   5 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
   6 *
   7 * Derived from "arch/i386/kernel/sys_i386.c"
   8 * Adapted from the i386 version by Gary Thomas
   9 * Modified by Cort Dougan (cort@cs.nmt.edu)
  10 * and Paul Mackerras (paulus@cs.anu.edu.au).
  11 *
  12 * This file contains various random system calls that
  13 * have a non-standard calling sequence on the Linux/PPC
  14 * platform.
  15 *
  16 *  This program is free software; you can redistribute it and/or
  17 *  modify it under the terms of the GNU General Public License
  18 *  as published by the Free Software Foundation; either version
  19 *  2 of the License, or (at your option) any later version.
  20 *
  21 */
  22
  23#include <linux/config.h>
  24#include <linux/errno.h>
  25#include <linux/sched.h>
  26#include <linux/mm.h>
  27#include <linux/smp.h>
  28#include <linux/smp_lock.h>
  29#include <linux/sem.h>
  30#include <linux/msg.h>
  31#include <linux/shm.h>
  32#include <linux/stat.h>
  33#include <linux/mman.h>
  34#include <linux/sys.h>
  35#include <linux/ipc.h>
  36#include <linux/utsname.h>
  37#include <linux/file.h>
  38
  39#include <asm/uaccess.h>
  40#include <asm/ipc.h>
  41#include <asm/semaphore.h>
  42
  43void
  44check_bugs(void)
  45{
  46}
  47
  48int sys_ioperm(unsigned long from, unsigned long num, int on)
  49{
  50        printk(KERN_ERR "sys_ioperm()\n");
  51        return -EIO;
  52}
  53
  54/*
  55 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  56 *
  57 * This is really horribly ugly.
  58 */
  59int
  60sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
  61{
  62        int version, ret;
  63
  64        version = call >> 16; /* hack for backward compatibility */
  65        call &= 0xffff;
  66
  67        ret = -EINVAL;
  68        switch (call) {
  69        case SEMOP:
  70                ret = sys_semtimedop(first, (struct sembuf *)ptr, second, NULL);
  71                break;
  72        case SEMTIMEDOP:
  73                ret = sys_semtimedop(first, (struct sembuf *)ptr, second,
  74                                     (const struct timespec *)fifth);
  75                break;
  76        case SEMGET:
  77                ret = sys_semget(first, second, third);
  78                break;
  79        case SEMCTL: {
  80                union semun fourth;
  81
  82                if (!ptr)
  83                        break;
  84                if ((ret = verify_area(VERIFY_READ, ptr, sizeof(long)))
  85                    || (ret = get_user(fourth.__pad, (void **)ptr)))
  86                        break;
  87                ret = sys_semctl(first, second, third, fourth);
  88                break;
  89                }
  90        case MSGSND:
  91                ret = sys_msgsnd(first, (struct msgbuf *) ptr, second, third);
  92                break;
  93        case MSGRCV:
  94                switch (version) {
  95                case 0: {
  96                        struct ipc_kludge tmp;
  97
  98                        if (!ptr)
  99                                break;
 100                        if ((ret = verify_area(VERIFY_READ, ptr, sizeof(tmp)))
 101                            || (ret = copy_from_user(&tmp,
 102                                                (struct ipc_kludge *) ptr,
 103                                                sizeof (tmp))))
 104                                break;
 105                        ret = sys_msgrcv(first, tmp.msgp, second, tmp.msgtyp,
 106                                         third);
 107                        break;
 108                        }
 109                default:
 110                        ret = sys_msgrcv(first, (struct msgbuf *) ptr,
 111                                         second, fifth, third);
 112                        break;
 113                }
 114                break;
 115        case MSGGET:
 116                ret = sys_msgget((key_t) first, second);
 117                break;
 118        case MSGCTL:
 119                ret = sys_msgctl(first, second, (struct msqid_ds *) ptr);
 120                break;
 121        case SHMAT:
 122                switch (version) {
 123                default: {
 124                        ulong raddr;
 125
 126                        if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
 127                                               sizeof(ulong))))
 128                                break;
 129                        ret = sys_shmat(first, (char *) ptr, second, &raddr);
 130                        if (ret)
 131                                break;
 132                        ret = put_user(raddr, (ulong *) third);
 133                        break;
 134                        }
 135                case 1: /* iBCS2 emulator entry point */
 136                        if (!segment_eq(get_fs(), get_ds()))
 137                                break;
 138                        ret = sys_shmat(first, (char *) ptr, second,
 139                                        (ulong *) third);
 140                        break;
 141                }
 142                break;
 143        case SHMDT:
 144                ret = sys_shmdt((char *)ptr);
 145                break;
 146        case SHMGET:
 147                ret = sys_shmget(first, second, third);
 148                break;
 149        case SHMCTL:
 150                ret = sys_shmctl(first, second, (struct shmid_ds *) ptr);
 151                break;
 152        default:
 153                ret = -ENOSYS;
 154        }
 155
 156        return ret;
 157}
 158
 159/*
 160 * sys_pipe() is the normal C calling standard for creating
 161 * a pipe. It's not the way unix traditionally does this, though.
 162 */
 163int sys_pipe(int *fildes)
 164{
 165        int fd[2];
 166        int error;
 167
 168        error = do_pipe(fd);
 169        if (!error) {
 170                if (copy_to_user(fildes, fd, 2*sizeof(int)))
 171                        error = -EFAULT;
 172        }
 173        return error;
 174}
 175
 176#ifndef CONFIG_40x
 177#define allow_mmap_address(addr)        1
 178#else
 179/* Blech.  On 40x allowing mmap() (MAP_FIXED) at the first few pages
 180 * of (any process's) virtual memory is a security hole due to chip
 181 * erratum #67 (and possibly also due to the (documented) bizarre
 182 * prefetch behaviour around 'sc' see S3.8.2.1 of the user manual). */
 183#define allow_mmap_address(addr)        ((((addr) & PAGE_MASK) >= 0x2100) || suser())
 184#endif
 185
 186static inline unsigned long
 187do_mmap2(unsigned long addr, size_t len,
 188         unsigned long prot, unsigned long flags,
 189         unsigned long fd, unsigned long pgoff)
 190{
 191        struct file * file = NULL;
 192        int ret = -EBADF;
 193
 194        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 195        if (!(flags & MAP_ANONYMOUS)) {
 196                if (!(file = fget(fd)))
 197                        goto out;
 198        }
 199
 200        ret = -EINVAL;
 201        if ((! allow_mmap_address(addr)) && (flags & MAP_FIXED))
 202                goto out;
 203        
 204        down_write(&current->mm->mmap_sem);
 205        ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 206        up_write(&current->mm->mmap_sem);
 207        if (file)
 208                fput(file);
 209out:
 210        return ret;
 211}
 212
 213unsigned long sys_mmap2(unsigned long addr, size_t len,
 214                        unsigned long prot, unsigned long flags,
 215                        unsigned long fd, unsigned long pgoff)
 216{
 217        return do_mmap2(addr, len, prot, flags, fd, pgoff);
 218}
 219
 220unsigned long sys_mmap(unsigned long addr, size_t len,
 221                       unsigned long prot, unsigned long flags,
 222                       unsigned long fd, off_t offset)
 223{
 224        int err = -EINVAL;
 225        unsigned long off = offset;
 226
 227        if (offset & ~PAGE_MASK)
 228                goto out;
 229
 230        err = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 231out:
 232        return err;
 233}
 234
 235extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 236
 237/*
 238 * Due to some executables calling the wrong select we sometimes
 239 * get wrong args.  This determines how the args are being passed
 240 * (a single ptr to them all args passed) then calls
 241 * sys_select() with the appropriate args. -- Cort
 242 */
 243int
 244ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 245{
 246        if ( (unsigned long)n >= 4096 )
 247        {
 248                unsigned long *buffer = (unsigned long *)n;
 249                if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
 250                    || __get_user(n, buffer)
 251                    || __get_user(inp, ((fd_set **)(buffer+1)))
 252                    || __get_user(outp, ((fd_set **)(buffer+2)))
 253                    || __get_user(exp, ((fd_set **)(buffer+3)))
 254                    || __get_user(tvp, ((struct timeval **)(buffer+4))))
 255                        return -EFAULT;
 256        }
 257        return sys_select(n, inp, outp, exp, tvp);
 258}
 259
 260int sys_pause(void)
 261{
 262        current->state = TASK_INTERRUPTIBLE;
 263        schedule();
 264        return -ERESTARTNOHAND;
 265}
 266
 267int sys_uname(struct old_utsname * name)
 268{
 269        int err = -EFAULT;
 270
 271        down_read(&uts_sem);
 272        if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
 273                err = 0;
 274        up_read(&uts_sem);
 275        return err;
 276}
 277
 278int sys_olduname(struct oldold_utsname * name)
 279{
 280        int error;
 281
 282        if (!name)
 283                return -EFAULT;
 284        if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 285                return -EFAULT;
 286
 287        down_read(&uts_sem);
 288        error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 289        error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
 290        error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
 291        error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
 292        error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
 293        error -= __put_user(0,name->release+__OLD_UTS_LEN);
 294        error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
 295        error -= __put_user(0,name->version+__OLD_UTS_LEN);
 296        error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 297        error = __put_user(0,name->machine+__OLD_UTS_LEN);
 298        up_read(&uts_sem);
 299
 300        error = error ? -EFAULT : 0;
 301        return error;
 302}
 303
 304#ifndef CONFIG_PCI
 305/*
 306 * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is
 307 * not defined, this file is not linked at all, so here are the "empty" versions
 308 */
 309int sys_pciconfig_read(void) { return -ENOSYS; }
 310int sys_pciconfig_write(void) { return -ENOSYS; }
 311long sys_pciconfig_iobase(void) { return -ENOSYS; }
 312#endif
 313
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.