clean
[linux-2.4.21-pre4.git] / arch / s390 / kernel / sys_s390.c
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  */
35 asmlinkage 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 */
49 static 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(&current->mm->mmap_sem);
65         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
66         up_write(&current->mm->mmap_sem);
67
68         if (file)
69                 fput(file);
70 out:
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
81 struct 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
90 asmlinkage 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);
98 out:
99         return error;
100 }
101
102 asmlinkage 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);
115 out:
116         return error;
117 }
118
119 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
120
121 struct sel_arg_struct {
122         unsigned long n;
123         fd_set *inp, *outp, *exp;
124         struct timeval *tvp;
125 };
126
127 asmlinkage 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  */
142 asmlinkage 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  */
204 asmlinkage 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
215 asmlinkage 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
244 asmlinkage int sys_pause(void)
245 {
246         set_current_state(TASK_INTERRUPTIBLE);
247         schedule();
248         return -ERESTARTNOHAND;
249 }
250
251 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
252 {
253   return -ENOSYS;
254 }
255