This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / arch / um / kernel / syscall_kern.c
1 /* 
2  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/sched.h"
7 #include "linux/file.h"
8 #include "linux/smp_lock.h"
9 #include "linux/mm.h"
10 #include "linux/utsname.h"
11 #include "linux/msg.h"
12 #include "linux/shm.h"
13 #include "linux/sys.h"
14 #include "linux/syscalls.h"
15 #include "linux/unistd.h"
16 #include "linux/slab.h"
17 #include "linux/utime.h"
18 #include "asm/mman.h"
19 #include "asm/uaccess.h"
20 #include "asm/ipc.h"
21 #include "kern_util.h"
22 #include "user_util.h"
23 #include "sysdep/syscalls.h"
24 #include "mode_kern.h"
25 #include "choose-mode.h"
26
27 /*  Unlocked, I don't care if this is a bit off */
28 int nsyscalls = 0;
29
30 long um_mount(char * dev_name, char * dir_name, char * type,
31               unsigned long new_flags, void * data)
32 {
33         if(type == NULL) type = "";
34         return(sys_mount(dev_name, dir_name, type, new_flags, data));
35 }
36
37 long sys_fork(void)
38 {
39         long ret;
40
41         current->thread.forking = 1;
42         ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
43         current->thread.forking = 0;
44         return(ret);
45 }
46
47 long sys_clone(unsigned long clone_flags, unsigned long newsp, 
48                int *parent_tid, int *child_tid)
49 {
50         long ret;
51
52         current->thread.forking = 1;
53         ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
54         current->thread.forking = 0;
55         return(ret);
56 }
57
58 long sys_vfork(void)
59 {
60         long ret;
61
62         current->thread.forking = 1;
63         ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, 
64                       NULL);
65         current->thread.forking = 0;
66         return(ret);
67 }
68
69 /* common code for old and new mmaps */
70 long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len,
71               unsigned long prot, unsigned long flags, unsigned long fd,
72               unsigned long pgoff)
73 {
74         int error = -EBADF;
75         struct file * file = NULL;
76
77         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
78         if (!(flags & MAP_ANONYMOUS)) {
79                 file = fget(fd);
80                 if (!file)
81                         goto out;
82         }
83
84         down_write(&mm->mmap_sem);
85         error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
86         up_write(&mm->mmap_sem);
87
88         if (file)
89                 fput(file);
90  out:
91         return error;
92 }
93
94 long sys_mmap2(unsigned long addr, unsigned long len,
95                unsigned long prot, unsigned long flags,
96                unsigned long fd, unsigned long pgoff)
97 {
98         return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
99 }
100
101 /*
102  * Perform the select(nd, in, out, ex, tv) and mmap() system
103  * calls. Linux/i386 didn't use to be able to handle more than
104  * 4 system call parameters, so these system calls used a memory
105  * block for parameter passing..
106  */
107
108 struct mmap_arg_struct {
109         unsigned long addr;
110         unsigned long len;
111         unsigned long prot;
112         unsigned long flags;
113         unsigned long fd;
114         unsigned long offset;
115 };
116
117 int old_mmap(unsigned long addr, unsigned long len,
118              unsigned long prot, unsigned long flags,
119              unsigned long fd, unsigned long offset)
120 {
121         int err = -EINVAL;
122         if (offset & ~PAGE_MASK)
123                 goto out;
124
125         err = do_mmap2(current->mm, addr, len, prot, flags, fd, 
126                        offset >> PAGE_SHIFT);
127  out:
128         return err;
129 }
130 /*
131  * sys_pipe() is the normal C calling standard for creating
132  * a pipe. It's not the way unix traditionally does this, though.
133  */
134 int sys_pipe(unsigned long * fildes)
135 {
136         int fd[2];
137         int error;
138
139         error = do_pipe(fd);
140         if (!error) {
141                 if (copy_to_user(fildes, fd, sizeof(fd)))
142                         error = -EFAULT;
143         }
144         return error;
145 }
146
147 /*
148  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
149  *
150  * This is really horribly ugly.
151  */
152 int sys_ipc (uint call, int first, int second,
153              int third, void *ptr, long fifth)
154 {
155         int version, ret;
156
157         version = call >> 16; /* hack for backward compatibility */
158         call &= 0xffff;
159
160         switch (call) {
161         case SEMOP:
162                 return sys_semtimedop(first, (struct sembuf *) ptr, second, 
163                                       NULL);
164         case SEMTIMEDOP:
165                 return sys_semtimedop(first, (struct sembuf *) ptr, second,
166                                       (const struct timespec *) fifth);
167         case SEMGET:
168                 return sys_semget (first, second, third);
169         case SEMCTL: {
170                 union semun fourth;
171                 if (!ptr)
172                         return -EINVAL;
173                 if (get_user(fourth.__pad, (void **) ptr))
174                         return -EFAULT;
175                 return sys_semctl (first, second, third, fourth);
176         }
177
178         case MSGSND:
179                 return sys_msgsnd (first, (struct msgbuf *) ptr, 
180                                    second, third);
181         case MSGRCV:
182                 switch (version) {
183                 case 0: {
184                         struct ipc_kludge tmp;
185                         if (!ptr)
186                                 return -EINVAL;
187                         
188                         if (copy_from_user(&tmp,
189                                            (struct ipc_kludge *) ptr, 
190                                            sizeof (tmp)))
191                                 return -EFAULT;
192                         return sys_msgrcv (first, tmp.msgp, second,
193                                            tmp.msgtyp, third);
194                 }
195                 default:
196                         panic("msgrcv with version != 0");
197                         return sys_msgrcv (first,
198                                            (struct msgbuf *) ptr,
199                                            second, fifth, third);
200                 }
201         case MSGGET:
202                 return sys_msgget ((key_t) first, second);
203         case MSGCTL:
204                 return sys_msgctl (first, second, (struct msqid_ds *) ptr);
205
206         case SHMAT:
207                 switch (version) {
208                 default: {
209                         ulong raddr;
210                         ret = do_shmat (first, (char *) ptr, second, &raddr);
211                         if (ret)
212                                 return ret;
213                         return put_user (raddr, (ulong *) third);
214                 }
215                 case 1: /* iBCS2 emulator entry point */
216                         if (!segment_eq(get_fs(), get_ds()))
217                                 return -EINVAL;
218                         return do_shmat (first, (char *) ptr, second, (ulong *) third);
219                 }
220         case SHMDT: 
221                 return sys_shmdt ((char *)ptr);
222         case SHMGET:
223                 return sys_shmget (first, second, third);
224         case SHMCTL:
225                 return sys_shmctl (first, second,
226                                    (struct shmid_ds *) ptr);
227         default:
228                 return -ENOSYS;
229         }
230 }
231
232 int sys_uname(struct old_utsname * name)
233 {
234         int err;
235         if (!name)
236                 return -EFAULT;
237         down_read(&uts_sem);
238         err=copy_to_user(name, vx_new_utsname(), sizeof (*name));
239         up_read(&uts_sem);
240         return err?-EFAULT:0;
241 }
242
243 int sys_olduname(struct oldold_utsname * name)
244 {
245         int error;
246         struct new_utsname *ptr;
247
248         if (!name)
249                 return -EFAULT;
250         if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
251                 return -EFAULT;
252   
253         down_read(&uts_sem);
254         
255         ptr = vx_new_utsname();
256         error = __copy_to_user(&name->sysname,ptr->sysname,
257                                __OLD_UTS_LEN);
258         error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
259         error |= __copy_to_user(&name->nodename,ptr->nodename,
260                                 __OLD_UTS_LEN);
261         error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
262         error |= __copy_to_user(&name->release,ptr->release,
263                                 __OLD_UTS_LEN);
264         error |= __put_user(0,name->release+__OLD_UTS_LEN);
265         error |= __copy_to_user(&name->version,ptr->version,
266                                 __OLD_UTS_LEN);
267         error |= __put_user(0,name->version+__OLD_UTS_LEN);
268         error |= __copy_to_user(&name->machine,ptr->machine,
269                                 __OLD_UTS_LEN);
270         error |= __put_user(0,name->machine+__OLD_UTS_LEN);
271         
272         up_read(&uts_sem);
273         
274         error = error ? -EFAULT : 0;
275
276         return error;
277 }
278
279 long execute_syscall(void *r)
280 {
281         return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
282 }
283
284 spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
285
286 static int syscall_index = 0;
287
288 int next_syscall_index(int limit)
289 {
290         int ret;
291
292         spin_lock(&syscall_lock);
293         ret = syscall_index;
294         if(++syscall_index == limit)
295                 syscall_index = 0;
296         spin_unlock(&syscall_lock);
297         return(ret);
298 }
299
300 /*
301  * Overrides for Emacs so that we follow Linus's tabbing style.
302  * Emacs will notice this stuff at the end of the file and automatically
303  * adjust the settings for this buffer only.  This must remain at the end
304  * of the file.
305  * ---------------------------------------------------------------------------
306  * Local variables:
307  * c-file-style: "linux"
308  * End:
309  */