1/* sys_frv.c: FRV arch-specific syscall wrappers
2 *
3 * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from arch/m68k/kernel/sys_m68k.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/sem.h>
18#include <linux/msg.h>
19#include <linux/shm.h>
20#include <linux/stat.h>
21#include <linux/mman.h>
22#include <linux/file.h>
23#include <linux/utsname.h>
24#include <linux/syscalls.h>
25
26#include <asm/setup.h>
27#include <asm/uaccess.h>
28#include <asm/ipc.h>
29
30/*
31 * sys_pipe() is the normal C calling standard for creating
32 * a pipe. It's not the way unix traditionally does this, though.
33 */
34asmlinkage long sys_pipe(unsigned long __user * fildes)
35{
36	int fd[2];
37	int error;
38
39	error = do_pipe(fd);
40	if (!error) {
41		if (copy_to_user(fildes, fd, 2*sizeof(int)))
42			error = -EFAULT;
43	}
44	return error;
45}
46
47asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
48			  unsigned long prot, unsigned long flags,
49			  unsigned long fd, unsigned long pgoff)
50{
51	int error = -EBADF;
52	struct file * file = NULL;
53
54	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
55	if (!(flags & MAP_ANONYMOUS)) {
56		file = fget(fd);
57		if (!file)
58			goto out;
59	}
60
61	/* As with sparc32, make sure the shift for mmap2 is constant
62	   (12), no matter what PAGE_SIZE we have.... */
63
64	/* But unlike sparc32, don't just silently break if we're
65	   trying to map something we can't */
66	if (pgoff & ((1<<(PAGE_SHIFT-12))-1))
67		return -EINVAL;
68
69	pgoff >>= (PAGE_SHIFT - 12);
70
71	down_write(&current->mm->mmap_sem);
72	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
73	up_write(&current->mm->mmap_sem);
74
75	if (file)
76		fput(file);
77out:
78	return error;
79}
80
81
82/*
83 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
84 *
85 * This is really horribly ugly.
86 */
87asmlinkage long sys_ipc(unsigned long call,
88			unsigned long first,
89			unsigned long second,
90			unsigned long third,
91			void __user *ptr,
92			unsigned long fifth)
93{
94	int version, ret;
95
96	version = call >> 16; /* hack for backward compatibility */
97	call &= 0xffff;
98
99	switch (call) {
100	case SEMOP:
101		return sys_semtimedop(first, (struct sembuf __user *)ptr, second, NULL);
102	case SEMTIMEDOP:
103		return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
104				      (const struct timespec __user *)fifth);
105
106	case SEMGET:
107		return sys_semget (first, second, third);
108	case SEMCTL: {
109		union semun fourth;
110		if (!ptr)
111			return -EINVAL;
112		if (get_user(fourth.__pad, (void * __user *) ptr))
113			return -EFAULT;
114		return sys_semctl (first, second, third, fourth);
115	}
116
117	case MSGSND:
118		return sys_msgsnd (first, (struct msgbuf __user *) ptr,
119				   second, third);
120	case MSGRCV:
121		switch (version) {
122		case 0: {
123			struct ipc_kludge tmp;
124			if (!ptr)
125				return -EINVAL;
126
127			if (copy_from_user(&tmp,
128					   (struct ipc_kludge __user *) ptr,
129					   sizeof (tmp)))
130				return -EFAULT;
131			return sys_msgrcv (first, tmp.msgp, second,
132					   tmp.msgtyp, third);
133		}
134		default:
135			return sys_msgrcv (first,
136					   (struct msgbuf __user *) ptr,
137					   second, fifth, third);
138		}
139	case MSGGET:
140		return sys_msgget ((key_t) first, second);
141	case MSGCTL:
142		return sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
143
144	case SHMAT:
145		switch (version) {
146		default: {
147			ulong raddr;
148			ret = do_shmat (first, (char __user *) ptr, second, &raddr);
149			if (ret)
150				return ret;
151			return put_user (raddr, (ulong __user *) third);
152		}
153		case 1:	/* iBCS2 emulator entry point */
154			if (!segment_eq(get_fs(), get_ds()))
155				return -EINVAL;
156			/* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
157			return do_shmat (first, (char __user *) ptr, second, (ulong *) third);
158		}
159	case SHMDT:
160		return sys_shmdt ((char __user *)ptr);
161	case SHMGET:
162		return sys_shmget (first, second, third);
163	case SHMCTL:
164		return sys_shmctl (first, second,
165				   (struct shmid_ds __user *) ptr);
166	default:
167		return -ENOSYS;
168	}
169}
170