[PATCH] consolidate sys_shmat
[linux-3.10.git] / arch / mips / kernel / syscall.c
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  * No implemented yet ...
378  */
379 asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
380 {
381         return -ENOSYS;
382 }
383
384 /*
385  * If we ever come here the user sp is bad.  Zap the process right away.
386  * Due to the bad stack signaling wouldn't work.
387  */
388 asmlinkage void bad_stack(void)
389 {
390         do_exit(SIGSEGV);
391 }