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#include <linux/personality.h>
28
29#include <asm/uaccess.h>
30#include <asm/ipc.h>
31
32/*
33 * sys_pipe() is the normal C calling standard for creating
34 * a pipe. It's not the way Unix traditionally does this, though.
35 */
36asmlinkage long sys_pipe(unsigned long * fildes)
37{
38	int fd[2];
39	int error;
40
41	error = do_pipe(fd);
42	if (!error) {
43		if (copy_to_user(fildes, fd, 2*sizeof(int)))
44			error = -EFAULT;
45	}
46	return error;
47}
48
49/* common code for old and new mmaps */
50static inline long do_mmap2(
51	unsigned long addr, unsigned long len,
52	unsigned long prot, unsigned long flags,
53	unsigned long fd, unsigned long pgoff)
54{
55	long error = -EBADF;
56	struct file * file = NULL;
57
58	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
59	if (!(flags & MAP_ANONYMOUS)) {
60		file = fget(fd);
61		if (!file)
62			goto out;
63	}
64
65	down_write(&current->mm->mmap_sem);
66	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
67	up_write(&current->mm->mmap_sem);
68
69	if (file)
70		fput(file);
71out:
72	return error;
73}
74
75/*
76 * Perform the select(nd, in, out, ex, tv) and mmap() system
77 * calls. Linux/i386 didn't use to be able to handle more than
78 * 4 system call parameters, so these system calls used a memory
79 * block for parameter passing..
80 */
81
82struct mmap_arg_struct {
83	unsigned long addr;
84	unsigned long len;
85	unsigned long prot;
86	unsigned long flags;
87	unsigned long fd;
88	unsigned long offset;
89};
90
91asmlinkage long sys_mmap2(struct mmap_arg_struct *arg)
92{
93	struct mmap_arg_struct a;
94	int error = -EFAULT;
95
96	if (copy_from_user(&a, arg, sizeof(a)))
97		goto out;
98	error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
99out:
100	return error;
101}
102
103asmlinkage long old_mmap(struct mmap_arg_struct *arg)
104{
105	struct mmap_arg_struct a;
106	long error = -EFAULT;
107
108	if (copy_from_user(&a, arg, sizeof(a)))
109		goto out;
110
111	error = -EINVAL;
112	if (a.offset & ~PAGE_MASK)
113		goto out;
114
115	error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
116out:
117	return error;
118}
119
120extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
121
122/*
123 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
124 *
125 * This is really horribly ugly.
126 */
127asmlinkage int sys_ipc (uint call, int first, long second,
128                        unsigned long third, void *ptr)
129{
130        struct ipc_kludge tmp;
131	int ret;
132
133        switch (call) {
134        case SEMOP:
135                return sys_semop (first, (struct sembuf *)ptr, second);
136        case SEMGET:
137                return sys_semget (first, second, third);
138        case SEMCTL: {
139                union semun fourth;
140                if (!ptr)
141                        return -EINVAL;
142                if (get_user(fourth.__pad, (void **) ptr))
143                        return -EFAULT;
144                return sys_semctl (first, second, third, fourth);
145        }
146        case MSGSND:
147		return sys_msgsnd (first, (struct msgbuf *) ptr,
148                                   second, third);
149		break;
150        case MSGRCV:
151                if (!ptr)
152                        return -EINVAL;
153                if (copy_from_user (&tmp, (struct ipc_kludge *) ptr,
154                                    sizeof (struct ipc_kludge)))
155                        return -EFAULT;
156                return sys_msgrcv (first, tmp.msgp,
157                                   second, tmp.msgtyp, third);
158        case MSGGET:
159                return sys_msgget ((key_t) first, second);
160        case MSGCTL:
161                return sys_msgctl (first, second, (struct msqid_ds *) ptr);
162
163	case SHMAT: {
164		ulong raddr;
165		ret = sys_shmat (first, (char *) ptr, second, &raddr);
166		if (ret)
167			return ret;
168		return put_user (raddr, (ulong *) third);
169		break;
170        }
171	case SHMDT:
172		return sys_shmdt ((char *)ptr);
173	case SHMGET:
174		return sys_shmget (first, second, third);
175	case SHMCTL:
176		return sys_shmctl (first, second,
177                                   (struct shmid_ds *) ptr);
178	default:
179		return -EINVAL;
180
181	}
182
183	return -EINVAL;
184}
185
186/*
187 * Old cruft
188 */
189asmlinkage int sys_uname(struct old_utsname * name)
190{
191	int err;
192	if (!name)
193		return -EFAULT;
194	down_read(&uts_sem);
195	err=copy_to_user(name, &system_utsname, sizeof (*name));
196	up_read(&uts_sem);
197	return err?-EFAULT:0;
198}
199
200asmlinkage int sys_pause(void)
201{
202	set_current_state(TASK_INTERRUPTIBLE);
203	schedule();
204	return -ERESTARTNOHAND;
205}
206
207extern asmlinkage int sys_newuname(struct new_utsname * name);
208
209asmlinkage int s390x_newuname(struct new_utsname * name)
210{
211	int ret = sys_newuname(name);
212
213	if (current->personality == PER_LINUX32 && !ret) {
214		ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
215		if (ret) ret = -EFAULT;
216	}
217	return ret;
218}
219
220extern asmlinkage long sys_personality(unsigned long);
221
222asmlinkage int s390x_personality(unsigned long personality)
223{
224	int ret;
225
226	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
227		personality = PER_LINUX32;
228	ret = sys_personality(personality);
229	if (ret == PER_LINUX32)
230		ret = PER_LINUX;
231
232	return ret;
233}
234