File: /usr/src/linux/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     
256