1/* 2 * arch/s390/kernel/sys_s390.c 3 * 4 * S390 version 5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation 6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), 7 * 8 * Derived from "arch/i386/kernel/sys_i386.c" 9 * 10 * This file contains various random system calls that 11 * have a non-standard calling sequence on the Linux/s390 12 * platform. 13 */ 14 15#include <linux/errno.h> 16#include <linux/sched.h> 17#include <linux/mm.h> 18#include <linux/smp.h> 19#include <linux/smp_lock.h> 20#include <linux/sem.h> 21#include <linux/msg.h> 22#include <linux/shm.h> 23#include <linux/stat.h> 24#include <linux/mman.h> 25#include <linux/file.h> 26#include <linux/utsname.h> 27 28#include <asm/uaccess.h> 29#include <asm/ipc.h> 30 31/* 32 * sys_pipe() is the normal C calling standard for creating 33 * a pipe. It's not the way Unix traditionally does this, though. 34 */ 35asmlinkage int sys_pipe(unsigned long * fildes) 36{ 37 int fd[2]; 38 int error; 39 40 error = do_pipe(fd); 41 if (!error) { 42 if (copy_to_user(fildes, fd, 2*sizeof(int))) 43 error = -EFAULT; 44 } 45 return error; 46} 47 48/* common code for old and new mmaps */ 49static inline long do_mmap2( 50 unsigned long addr, unsigned long len, 51 unsigned long prot, unsigned long flags, 52 unsigned long fd, unsigned long pgoff) 53{ 54 int error = -EBADF; 55 struct file * file = NULL; 56 57 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 58 if (!(flags & MAP_ANONYMOUS)) { 59 file = fget(fd); 60 if (!file) 61 goto out; 62 } 63 64 down_write(¤t->mm->mmap_sem); 65 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 66 up_write(¤t->mm->mmap_sem); 67 68 if (file) 69 fput(file); 70out: 71 return error; 72} 73 74/* 75 * Perform the select(nd, in, out, ex, tv) and mmap() system 76 * calls. Linux for S/390 isn't able to handle more than 5 77 * system call parameters, so these system calls used a memory 78 * block for parameter passing.. 79 */ 80 81struct mmap_arg_struct { 82 unsigned long addr; 83 unsigned long len; 84 unsigned long prot; 85 unsigned long flags; 86 unsigned long fd; 87 unsigned long offset; 88}; 89 90asmlinkage long sys_mmap2(struct mmap_arg_struct *arg) 91{ 92 struct mmap_arg_struct a; 93 int error = -EFAULT; 94 95 if (copy_from_user(&a, arg, sizeof(a))) 96 goto out; 97 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); 98out: 99 return error; 100} 101 102asmlinkage int old_mmap(struct mmap_arg_struct *arg) 103{ 104 struct mmap_arg_struct a; 105 int error = -EFAULT; 106 107 if (copy_from_user(&a, arg, sizeof(a))) 108 goto out; 109 110 error = -EINVAL; 111 if (a.offset & ~PAGE_MASK) 112 goto out; 113 114 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); 115out: 116 return error; 117} 118 119extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); 120 121struct sel_arg_struct { 122 unsigned long n; 123 fd_set *inp, *outp, *exp; 124 struct timeval *tvp; 125}; 126 127asmlinkage int old_select(struct sel_arg_struct *arg) 128{ 129 struct sel_arg_struct a; 130 131 if (copy_from_user(&a, arg, sizeof(a))) 132 return -EFAULT; 133 /* sys_select() does the appropriate kernel locking */ 134 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); 135} 136 137/* 138 * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 139 * 140 * This is really horribly ugly. 141 */ 142asmlinkage int sys_ipc (uint call, int first, int second, 143 int third, void *ptr) 144{ 145 struct ipc_kludge tmp; 146 int ret; 147 148 switch (call) { 149 case SEMOP: 150 return sys_semop (first, (struct sembuf *)ptr, second); 151 case SEMGET: 152 return sys_semget (first, second, third); 153 case SEMCTL: { 154 union semun fourth; 155 if (!ptr) 156 return -EINVAL; 157 if (get_user(fourth.__pad, (void **) ptr)) 158 return -EFAULT; 159 return sys_semctl (first, second, third, fourth); 160 } 161 case MSGSND: 162 return sys_msgsnd (first, (struct msgbuf *) ptr, 163 second, third); 164 break; 165 case MSGRCV: 166 if (!ptr) 167 return -EINVAL; 168 if (copy_from_user (&tmp, (struct ipc_kludge *) ptr, 169 sizeof (struct ipc_kludge))) 170 return -EFAULT; 171 return sys_msgrcv (first, tmp.msgp, 172 second, tmp.msgtyp, third); 173 case MSGGET: 174 return sys_msgget ((key_t) first, second); 175 case MSGCTL: 176 return sys_msgctl (first, second, (struct msqid_ds *) ptr); 177 178 case SHMAT: { 179 ulong raddr; 180 ret = sys_shmat (first, (char *) ptr, second, &raddr); 181 if (ret) 182 return ret; 183 return put_user (raddr, (ulong *) third); 184 break; 185 } 186 case SHMDT: 187 return sys_shmdt ((char *)ptr); 188 case SHMGET: 189 return sys_shmget (first, second, third); 190 case SHMCTL: 191 return sys_shmctl (first, second, 192 (struct shmid_ds *) ptr); 193 default: 194 return -EINVAL; 195 196 } 197 198 return -EINVAL; 199} 200 201/* 202 * Old cruft 203 */ 204asmlinkage int sys_uname(struct old_utsname * name) 205{ 206 int err; 207 if (!name) 208 return -EFAULT; 209 down_read(&uts_sem); 210 err=copy_to_user(name, &system_utsname, sizeof (*name)); 211 up_read(&uts_sem); 212 return err?-EFAULT:0; 213} 214 215asmlinkage int sys_olduname(struct oldold_utsname * name) 216{ 217 int error; 218 219 if (!name) 220 return -EFAULT; 221 if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) 222 return -EFAULT; 223 224 down_read(&uts_sem); 225 226 error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); 227 error |= __put_user(0,name->sysname+__OLD_UTS_LEN); 228 error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); 229 error |= __put_user(0,name->nodename+__OLD_UTS_LEN); 230 error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); 231 error |= __put_user(0,name->release+__OLD_UTS_LEN); 232 error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); 233 error |= __put_user(0,name->version+__OLD_UTS_LEN); 234 error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); 235 error |= __put_user(0,name->machine+__OLD_UTS_LEN); 236 237 up_read(&uts_sem); 238 239 error = error ? -EFAULT : 0; 240 241 return error; 242} 243 244asmlinkage int sys_pause(void) 245{ 246 set_current_state(TASK_INTERRUPTIBLE); 247 schedule(); 248 return -ERESTARTNOHAND; 249} 250 251asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) 252{ 253 return -ENOSYS; 254} 255 256