Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/hpa/linux...
[linux-2.6] / arch / m68knommu / kernel / sys_m68k.c
1 /*
2  * linux/arch/m68knommu/kernel/sys_m68k.c
3  *
4  * This file contains various random system calls that
5  * have a non-standard calling sequence on the Linux/m68k
6  * platform.
7  */
8
9 #include <linux/errno.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/smp.h>
13 #include <linux/sem.h>
14 #include <linux/msg.h>
15 #include <linux/shm.h>
16 #include <linux/stat.h>
17 #include <linux/syscalls.h>
18 #include <linux/mman.h>
19 #include <linux/file.h>
20 #include <linux/utsname.h>
21 #include <linux/ipc.h>
22 #include <linux/fs.h>
23
24 #include <asm/setup.h>
25 #include <asm/uaccess.h>
26 #include <asm/cachectl.h>
27 #include <asm/traps.h>
28 #include <asm/cacheflush.h>
29 #include <asm/unistd.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 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
75         unsigned long prot, unsigned long flags,
76         unsigned long fd, unsigned long pgoff)
77 {
78         return do_mmap2(addr, len, prot, flags, fd, pgoff);
79 }
80
81 /*
82  * Perform the select(nd, in, out, ex, tv) and mmap() system
83  * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
84  * handle more than 4 system call parameters, so these system calls
85  * used a memory block for parameter passing..
86  */
87
88 struct mmap_arg_struct {
89         unsigned long addr;
90         unsigned long len;
91         unsigned long prot;
92         unsigned long flags;
93         unsigned long fd;
94         unsigned long offset;
95 };
96
97 asmlinkage int old_mmap(struct mmap_arg_struct *arg)
98 {
99         struct mmap_arg_struct a;
100         int error = -EFAULT;
101
102         if (copy_from_user(&a, arg, sizeof(a)))
103                 goto out;
104
105         error = -EINVAL;
106         if (a.offset & ~PAGE_MASK)
107                 goto out;
108
109         a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
110
111         error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
112 out:
113         return error;
114 }
115
116 struct sel_arg_struct {
117         unsigned long n;
118         fd_set *inp, *outp, *exp;
119         struct timeval *tvp;
120 };
121
122 asmlinkage int old_select(struct sel_arg_struct *arg)
123 {
124         struct sel_arg_struct a;
125
126         if (copy_from_user(&a, arg, sizeof(a)))
127                 return -EFAULT;
128         /* sys_select() does the appropriate kernel locking */
129         return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
130 }
131
132 /*
133  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
134  *
135  * This is really horribly ugly.
136  */
137 asmlinkage int sys_ipc (uint call, int first, int second,
138                         int third, void *ptr, long fifth)
139 {
140         int version, ret;
141
142         version = call >> 16; /* hack for backward compatibility */
143         call &= 0xffff;
144
145         if (call <= SEMCTL)
146                 switch (call) {
147                 case SEMOP:
148                         return sys_semop (first, (struct sembuf *)ptr, second);
149                 case SEMGET:
150                         return sys_semget (first, second, third);
151                 case SEMCTL: {
152                         union semun fourth;
153                         if (!ptr)
154                                 return -EINVAL;
155                         if (get_user(fourth.__pad, (void **) ptr))
156                                 return -EFAULT;
157                         return sys_semctl (first, second, third, fourth);
158                         }
159                 default:
160                         return -EINVAL;
161                 }
162         if (call <= MSGCTL) 
163                 switch (call) {
164                 case MSGSND:
165                         return sys_msgsnd (first, (struct msgbuf *) ptr, 
166                                           second, third);
167                 case MSGRCV:
168                         switch (version) {
169                         case 0: {
170                                 struct ipc_kludge tmp;
171                                 if (!ptr)
172                                         return -EINVAL;
173                                 if (copy_from_user (&tmp,
174                                                     (struct ipc_kludge *)ptr,
175                                                     sizeof (tmp)))
176                                         return -EFAULT;
177                                 return sys_msgrcv (first, tmp.msgp, second,
178                                                    tmp.msgtyp, third);
179                                 }
180                         default:
181                                 return sys_msgrcv (first,
182                                                    (struct msgbuf *) ptr,
183                                                    second, fifth, third);
184                         }
185                 case MSGGET:
186                         return sys_msgget ((key_t) first, second);
187                 case MSGCTL:
188                         return sys_msgctl (first, second,
189                                            (struct msqid_ds *) ptr);
190                 default:
191                         return -EINVAL;
192                 }
193         if (call <= SHMCTL)
194                 switch (call) {
195                 case SHMAT:
196                         switch (version) {
197                         default: {
198                                 ulong raddr;
199                                 ret = do_shmat (first, ptr, second, &raddr);
200                                 if (ret)
201                                         return ret;
202                                 return put_user (raddr, (ulong __user *) third);
203                         }
204                         }
205                 case SHMDT:
206                         return sys_shmdt (ptr);
207                 case SHMGET:
208                         return sys_shmget (first, second, third);
209                 case SHMCTL:
210                         return sys_shmctl (first, second, ptr);
211                 default:
212                         return -ENOSYS;
213                 }
214
215         return -EINVAL;
216 }
217
218 /* sys_cacheflush -- flush (part of) the processor cache.  */
219 asmlinkage int
220 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
221 {
222         flush_cache_all();
223         return(0);
224 }
225
226 asmlinkage int sys_getpagesize(void)
227 {
228         return PAGE_SIZE;
229 }
230
231 /*
232  * Do a system call from kernel instead of calling sys_execve so we
233  * end up with proper pt_regs.
234  */
235 int kernel_execve(const char *filename, char *const argv[], char *const envp[])
236 {
237         register long __res asm ("%d0") = __NR_execve;
238         register long __a asm ("%d1") = (long)(filename);
239         register long __b asm ("%d2") = (long)(argv);
240         register long __c asm ("%d3") = (long)(envp);
241         asm volatile ("trap  #0" : "+d" (__res)
242                         : "d" (__a), "d" (__b), "d" (__c));
243         return __res;
244 }