5f17a1ebc8253e658e49b173e11c8efaeedcd3ac
[linux-3.10.git] / arch / mn10300 / kernel / sys_mn10300.c
1 /* MN10300 Weird system calls
2  *
3  * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #include <linux/errno.h>
12 #include <linux/sched.h>
13 #include <linux/syscalls.h>
14 #include <linux/mm.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.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 #include <linux/tty.h>
26
27 #include <asm/uaccess.h>
28
29 #define MIN_MAP_ADDR    PAGE_SIZE       /* minimum fixed mmap address */
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 long sys_pipe(unsigned long __user *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 /*
49  * memory mapping syscall
50  */
51 asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
52                           unsigned long prot, unsigned long flags,
53                           unsigned long fd, unsigned long pgoff)
54 {
55         struct file *file = NULL;
56         long error = -EINVAL;
57
58         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
59
60         if (flags & MAP_FIXED && addr < MIN_MAP_ADDR)
61                 goto out;
62
63         error = -EBADF;
64         if (!(flags & MAP_ANONYMOUS)) {
65                 file = fget(fd);
66                 if (!file)
67                         goto out;
68         }
69
70         down_write(&current->mm->mmap_sem);
71         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
72         up_write(&current->mm->mmap_sem);
73
74         if (file)
75                 fput(file);
76 out:
77         return error;
78 }
79
80 asmlinkage long old_mmap(unsigned long addr, unsigned long len,
81                          unsigned long prot, unsigned long flags,
82                          unsigned long fd, unsigned long offset)
83 {
84         if (offset & ~PAGE_MASK)
85                 return -EINVAL;
86         return sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
87 }
88
89 struct sel_arg_struct {
90         unsigned long n;
91         fd_set *inp;
92         fd_set *outp;
93         fd_set *exp;
94         struct timeval *tvp;
95 };
96
97 asmlinkage int old_select(struct sel_arg_struct __user *arg)
98 {
99         struct sel_arg_struct a;
100
101         if (copy_from_user(&a, arg, sizeof(a)))
102                 return -EFAULT;
103         /* sys_select() does the appropriate kernel locking */
104         return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
105 }
106
107 /*
108  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
109  *
110  * This is really horribly ugly.
111  */
112 asmlinkage long sys_ipc(uint call, int first, int second,
113                         int third, void __user *ptr, long fifth)
114 {
115         int version, ret;
116
117         version = call >> 16; /* hack for backward compatibility */
118         call &= 0xffff;
119
120         switch (call) {
121         case SEMOP:
122                 return sys_semtimedop(first, (struct sembuf __user *)ptr,
123                                       second, NULL);
124         case SEMTIMEDOP:
125                 return sys_semtimedop(first, (struct sembuf __user *)ptr,
126                                       second,
127                                       (const struct timespec __user *)fifth);
128         case SEMGET:
129                 return sys_semget(first, second, third);
130         case SEMCTL: {
131                 union semun fourth;
132                 if (!ptr)
133                         return -EINVAL;
134                 if (get_user(fourth.__pad, (void __user * __user *) ptr))
135                         return -EFAULT;
136                 return sys_semctl(first, second, third, fourth);
137         }
138
139         case MSGSND:
140                 return sys_msgsnd(first, (struct msgbuf __user *) ptr,
141                                   second, third);
142         case MSGRCV:
143                 switch (version) {
144                 case 0: {
145                         struct ipc_kludge tmp;
146                         if (!ptr)
147                                 return -EINVAL;
148
149                         if (copy_from_user(&tmp,
150                                            (struct ipc_kludge __user *) ptr,
151                                            sizeof(tmp)))
152                                 return -EFAULT;
153                         return sys_msgrcv(first, tmp.msgp, second,
154                                           tmp.msgtyp, third);
155                 }
156                 default:
157                         return sys_msgrcv(first,
158                                           (struct msgbuf __user *) ptr,
159                                            second, fifth, third);
160                 }
161         case MSGGET:
162                 return sys_msgget((key_t) first, second);
163         case MSGCTL:
164                 return sys_msgctl(first, second,
165                                    (struct msqid_ds __user *) ptr);
166
167         case SHMAT:
168                 switch (version) {
169                 default: {
170                         ulong raddr;
171                         ret = do_shmat(first, (char __user *) ptr, second,
172                                        &raddr);
173                         if (ret)
174                                 return ret;
175                         return put_user(raddr, (ulong *) third);
176                 }
177                 case 1: /* iBCS2 emulator entry point */
178                         if (!segment_eq(get_fs(), get_ds()))
179                                 return -EINVAL;
180                         return do_shmat(first, (char __user *) ptr, second,
181                                         (ulong *) third);
182                 }
183         case SHMDT:
184                 return sys_shmdt((char __user *)ptr);
185         case SHMGET:
186                 return sys_shmget(first, second, third);
187         case SHMCTL:
188                 return sys_shmctl(first, second,
189                                   (struct shmid_ds __user *) ptr);
190         default:
191                 return -EINVAL;
192         }
193 }