xref: /openbmc/linux/arch/mips/kernel/syscall.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1995, 1996, 1997, 2000, 2001, 05 by Ralf Baechle
7  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8  * Copyright (C) 2001 MIPS Technologies, Inc.
9  */
10 #include <linux/a.out.h>
11 #include <linux/errno.h>
12 #include <linux/linkage.h>
13 #include <linux/mm.h>
14 #include <linux/smp.h>
15 #include <linux/smp_lock.h>
16 #include <linux/mman.h>
17 #include <linux/ptrace.h>
18 #include <linux/sched.h>
19 #include <linux/string.h>
20 #include <linux/syscalls.h>
21 #include <linux/file.h>
22 #include <linux/slab.h>
23 #include <linux/utsname.h>
24 #include <linux/unistd.h>
25 #include <linux/sem.h>
26 #include <linux/msg.h>
27 #include <linux/shm.h>
28 #include <linux/compiler.h>
29 
30 #include <asm/branch.h>
31 #include <asm/cachectl.h>
32 #include <asm/cacheflush.h>
33 #include <asm/ipc.h>
34 #include <asm/offset.h>
35 #include <asm/signal.h>
36 #include <asm/sim.h>
37 #include <asm/shmparam.h>
38 #include <asm/sysmips.h>
39 #include <asm/uaccess.h>
40 
41 asmlinkage int sys_pipe(nabi_no_regargs volatile struct pt_regs regs)
42 {
43 	int fd[2];
44 	int error, res;
45 
46 	error = do_pipe(fd);
47 	if (error) {
48 		res = error;
49 		goto out;
50 	}
51 	regs.regs[3] = fd[1];
52 	res = fd[0];
53 out:
54 	return res;
55 }
56 
57 unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
58 
59 #define COLOUR_ALIGN(addr,pgoff)				\
60 	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
61 	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
62 
63 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
64 	unsigned long len, unsigned long pgoff, unsigned long flags)
65 {
66 	struct vm_area_struct * vmm;
67 	int do_color_align;
68 	unsigned long task_size;
69 
70 	task_size = STACK_TOP;
71 
72 	if (flags & MAP_FIXED) {
73 		/*
74 		 * We do not accept a shared mapping if it would violate
75 		 * cache aliasing constraints.
76 		 */
77 		if ((flags & MAP_SHARED) && (addr & shm_align_mask))
78 			return -EINVAL;
79 		return addr;
80 	}
81 
82 	if (len > task_size)
83 		return -ENOMEM;
84 	do_color_align = 0;
85 	if (filp || (flags & MAP_SHARED))
86 		do_color_align = 1;
87 	if (addr) {
88 		if (do_color_align)
89 			addr = COLOUR_ALIGN(addr, pgoff);
90 		else
91 			addr = PAGE_ALIGN(addr);
92 		vmm = find_vma(current->mm, addr);
93 		if (task_size - len >= addr &&
94 		    (!vmm || addr + len <= vmm->vm_start))
95 			return addr;
96 	}
97 	addr = TASK_UNMAPPED_BASE;
98 	if (do_color_align)
99 		addr = COLOUR_ALIGN(addr, pgoff);
100 	else
101 		addr = PAGE_ALIGN(addr);
102 
103 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
104 		/* At this point:  (!vmm || addr < vmm->vm_end). */
105 		if (task_size - len < addr)
106 			return -ENOMEM;
107 		if (!vmm || addr + len <= vmm->vm_start)
108 			return addr;
109 		addr = vmm->vm_end;
110 		if (do_color_align)
111 			addr = COLOUR_ALIGN(addr, pgoff);
112 	}
113 }
114 
115 /* common code for old and new mmaps */
116 static inline unsigned long
117 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
118         unsigned long flags, unsigned long fd, unsigned long pgoff)
119 {
120 	unsigned long error = -EBADF;
121 	struct file * file = NULL;
122 
123 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
124 	if (!(flags & MAP_ANONYMOUS)) {
125 		file = fget(fd);
126 		if (!file)
127 			goto out;
128 	}
129 
130 	down_write(&current->mm->mmap_sem);
131 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
132 	up_write(&current->mm->mmap_sem);
133 
134 	if (file)
135 		fput(file);
136 out:
137 	return error;
138 }
139 
140 asmlinkage unsigned long
141 old_mmap(unsigned long addr, unsigned long len, int prot,
142 	int flags, int fd, off_t offset)
143 {
144 	unsigned long result;
145 
146 	result = -EINVAL;
147 	if (offset & ~PAGE_MASK)
148 		goto out;
149 
150 	result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
151 
152 out:
153 	return result;
154 }
155 
156 asmlinkage unsigned long
157 sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
158           unsigned long flags, unsigned long fd, unsigned long pgoff)
159 {
160 	return do_mmap2(addr, len, prot, flags, fd, pgoff);
161 }
162 
163 save_static_function(sys_fork);
164 __attribute_used__ noinline static int
165 _sys_fork(nabi_no_regargs struct pt_regs regs)
166 {
167 	return do_fork(SIGCHLD, regs.regs[29], &regs, 0, NULL, NULL);
168 }
169 
170 save_static_function(sys_clone);
171 __attribute_used__ noinline static int
172 _sys_clone(nabi_no_regargs struct pt_regs regs)
173 {
174 	unsigned long clone_flags;
175 	unsigned long newsp;
176 	int *parent_tidptr, *child_tidptr;
177 
178 	clone_flags = regs.regs[4];
179 	newsp = regs.regs[5];
180 	if (!newsp)
181 		newsp = regs.regs[29];
182 	parent_tidptr = (int *) regs.regs[6];
183 	child_tidptr = (int *) regs.regs[7];
184 	return do_fork(clone_flags, newsp, &regs, 0,
185 	               parent_tidptr, child_tidptr);
186 }
187 
188 /*
189  * sys_execve() executes a new program.
190  */
191 asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
192 {
193 	int error;
194 	char * filename;
195 
196 	filename = getname((char *) (long)regs.regs[4]);
197 	error = PTR_ERR(filename);
198 	if (IS_ERR(filename))
199 		goto out;
200 	error = do_execve(filename, (char **) (long)regs.regs[5],
201 	                  (char **) (long)regs.regs[6], &regs);
202 	putname(filename);
203 
204 out:
205 	return error;
206 }
207 
208 /*
209  * Compacrapability ...
210  */
211 asmlinkage int sys_uname(struct old_utsname * name)
212 {
213 	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
214 		return 0;
215 	return -EFAULT;
216 }
217 
218 /*
219  * Compacrapability ...
220  */
221 asmlinkage int sys_olduname(struct oldold_utsname * name)
222 {
223 	int error;
224 
225 	if (!name)
226 		return -EFAULT;
227 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
228 		return -EFAULT;
229 
230 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
231 	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
232 	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
233 	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
234 	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
235 	error -= __put_user(0,name->release+__OLD_UTS_LEN);
236 	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
237 	error -= __put_user(0,name->version+__OLD_UTS_LEN);
238 	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
239 	error = __put_user(0,name->machine+__OLD_UTS_LEN);
240 	error = error ? -EFAULT : 0;
241 
242 	return error;
243 }
244 
245 asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
246 {
247 	int	tmp, len;
248 	char	*name;
249 
250 	switch(cmd) {
251 	case SETNAME: {
252 		char nodename[__NEW_UTS_LEN + 1];
253 
254 		if (!capable(CAP_SYS_ADMIN))
255 			return -EPERM;
256 
257 		name = (char *) arg1;
258 
259 		len = strncpy_from_user(nodename, name, __NEW_UTS_LEN);
260 		if (len < 0)
261 			return -EFAULT;
262 
263 		down_write(&uts_sem);
264 		strncpy(system_utsname.nodename, nodename, len);
265 		nodename[__NEW_UTS_LEN] = '\0';
266 		strlcpy(system_utsname.nodename, nodename,
267 		        sizeof(system_utsname.nodename));
268 		up_write(&uts_sem);
269 		return 0;
270 	}
271 
272 	case MIPS_ATOMIC_SET:
273 		printk(KERN_CRIT "How did I get here?\n");
274 		return -EINVAL;
275 
276 	case MIPS_FIXADE:
277 		tmp = current->thread.mflags & ~3;
278 		current->thread.mflags = tmp | (arg1 & 3);
279 		return 0;
280 
281 	case FLUSH_CACHE:
282 		__flush_cache_all();
283 		return 0;
284 
285 	case MIPS_RDNVRAM:
286 		return -EIO;
287 	}
288 
289 	return -EINVAL;
290 }
291 
292 /*
293  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
294  *
295  * This is really horribly ugly.
296  */
297 asmlinkage int sys_ipc (uint call, int first, int second,
298 			unsigned long third, void *ptr, long fifth)
299 {
300 	int version, ret;
301 
302 	version = call >> 16; /* hack for backward compatibility */
303 	call &= 0xffff;
304 
305 	switch (call) {
306 	case SEMOP:
307 		return sys_semtimedop (first, (struct sembuf *)ptr, second,
308 		                       NULL);
309 	case SEMTIMEDOP:
310 		return sys_semtimedop (first, (struct sembuf *)ptr, second,
311 		                       (const struct timespec __user *)fifth);
312 	case SEMGET:
313 		return sys_semget (first, second, third);
314 	case SEMCTL: {
315 		union semun fourth;
316 		if (!ptr)
317 			return -EINVAL;
318 		if (get_user(fourth.__pad, (void **) ptr))
319 			return -EFAULT;
320 		return sys_semctl (first, second, third, fourth);
321 	}
322 
323 	case MSGSND:
324 		return sys_msgsnd (first, (struct msgbuf *) ptr,
325 				   second, third);
326 	case MSGRCV:
327 		switch (version) {
328 		case 0: {
329 			struct ipc_kludge tmp;
330 			if (!ptr)
331 				return -EINVAL;
332 
333 			if (copy_from_user(&tmp,
334 					   (struct ipc_kludge *) ptr,
335 					   sizeof (tmp)))
336 				return -EFAULT;
337 			return sys_msgrcv (first, tmp.msgp, second,
338 					   tmp.msgtyp, third);
339 		}
340 		default:
341 			return sys_msgrcv (first,
342 					   (struct msgbuf *) ptr,
343 					   second, fifth, third);
344 		}
345 	case MSGGET:
346 		return sys_msgget ((key_t) first, second);
347 	case MSGCTL:
348 		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
349 
350 	case SHMAT:
351 		switch (version) {
352 		default: {
353 			ulong raddr;
354 			ret = do_shmat (first, (char *) ptr, second, &raddr);
355 			if (ret)
356 				return ret;
357 			return put_user (raddr, (ulong *) third);
358 		}
359 		case 1:	/* iBCS2 emulator entry point */
360 			if (!segment_eq(get_fs(), get_ds()))
361 				return -EINVAL;
362 			return do_shmat (first, (char *) ptr, second, (ulong *) third);
363 		}
364 	case SHMDT:
365 		return sys_shmdt ((char *)ptr);
366 	case SHMGET:
367 		return sys_shmget (first, second, third);
368 	case SHMCTL:
369 		return sys_shmctl (first, second,
370 				   (struct shmid_ds *) ptr);
371 	default:
372 		return -ENOSYS;
373 	}
374 }
375 
376 /*
377  * Native ABI that is O32 or N64 version
378  */
379 asmlinkage long sys_shmat(int shmid, char __user *shmaddr,
380                           int shmflg, unsigned long *addr)
381 {
382 	unsigned long raddr;
383 	int err;
384 
385 	err = do_shmat(shmid, shmaddr, shmflg, &raddr);
386 	if (err)
387 		return err;
388 
389 	return put_user(raddr, addr);
390 }
391 
392 /*
393  * No implemented yet ...
394  */
395 asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
396 {
397 	return -ENOSYS;
398 }
399 
400 /*
401  * If we ever come here the user sp is bad.  Zap the process right away.
402  * Due to the bad stack signaling wouldn't work.
403  */
404 asmlinkage void bad_stack(void)
405 {
406 	do_exit(SIGSEGV);
407 }
408