Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-leds
[linux-2.6] / arch / um / sys-i386 / syscalls.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/shm.h"
8 #include "linux/ipc.h"
9 #include "linux/syscalls.h"
10 #include "asm/mman.h"
11 #include "asm/uaccess.h"
12 #include "asm/unistd.h"
13
14 /*
15  * Perform the select(nd, in, out, ex, tv) and mmap() system
16  * calls. Linux/i386 didn't use to be able to handle more than
17  * 4 system call parameters, so these system calls used a memory
18  * block for parameter passing..
19  */
20
21 struct mmap_arg_struct {
22         unsigned long addr;
23         unsigned long len;
24         unsigned long prot;
25         unsigned long flags;
26         unsigned long fd;
27         unsigned long offset;
28 };
29
30 extern int old_mmap(unsigned long addr, unsigned long len,
31                     unsigned long prot, unsigned long flags,
32                     unsigned long fd, unsigned long offset);
33
34 long old_mmap_i386(struct mmap_arg_struct __user *arg)
35 {
36         struct mmap_arg_struct a;
37         int err = -EFAULT;
38
39         if (copy_from_user(&a, arg, sizeof(a)))
40                 goto out;
41
42         err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
43  out:
44         return err;
45 }
46
47 struct sel_arg_struct {
48         unsigned long n;
49         fd_set __user *inp;
50         fd_set __user *outp;
51         fd_set __user *exp;
52         struct timeval __user *tvp;
53 };
54
55 long old_select(struct sel_arg_struct __user *arg)
56 {
57         struct sel_arg_struct a;
58
59         if (copy_from_user(&a, arg, sizeof(a)))
60                 return -EFAULT;
61         /* sys_select() does the appropriate kernel locking */
62         return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
63 }
64
65 /*
66  * The prototype on i386 is:
67  *
68  *     int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
69  *
70  * and the "newtls" arg. on i386 is read by copy_thread directly from the
71  * register saved on the stack.
72  */
73 long sys_clone(unsigned long clone_flags, unsigned long newsp,
74                int __user *parent_tid, void *newtls, int __user *child_tid)
75 {
76         long ret;
77
78         if (!newsp)
79                 newsp = UPT_SP(&current->thread.regs.regs);
80
81         current->thread.forking = 1;
82         ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
83                       child_tid);
84         current->thread.forking = 0;
85         return ret;
86 }
87
88 /*
89  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
90  *
91  * This is really horribly ugly.
92  */
93 long sys_ipc (uint call, int first, int second,
94              int third, void __user *ptr, long fifth)
95 {
96         int version, ret;
97
98         version = call >> 16; /* hack for backward compatibility */
99         call &= 0xffff;
100
101         switch (call) {
102         case SEMOP:
103                 return sys_semtimedop(first, (struct sembuf __user *) ptr,
104                                       second, NULL);
105         case SEMTIMEDOP:
106                 return sys_semtimedop(first, (struct sembuf __user *) ptr,
107                                       second,
108                                       (const struct timespec __user *) fifth);
109         case SEMGET:
110                 return sys_semget (first, second, third);
111         case SEMCTL: {
112                 union semun fourth;
113                 if (!ptr)
114                         return -EINVAL;
115                 if (get_user(fourth.__pad, (void __user * __user *) ptr))
116                         return -EFAULT;
117                 return sys_semctl (first, second, third, fourth);
118         }
119
120         case MSGSND:
121                 return sys_msgsnd (first, (struct msgbuf *) ptr,
122                                    second, third);
123         case MSGRCV:
124                 switch (version) {
125                 case 0: {
126                         struct ipc_kludge tmp;
127                         if (!ptr)
128                                 return -EINVAL;
129
130                         if (copy_from_user(&tmp,
131                                            (struct ipc_kludge *) ptr,
132                                            sizeof (tmp)))
133                                 return -EFAULT;
134                         return sys_msgrcv (first, tmp.msgp, second,
135                                            tmp.msgtyp, third);
136                 }
137                 default:
138                         panic("msgrcv with version != 0");
139                         return sys_msgrcv (first,
140                                            (struct msgbuf *) ptr,
141                                            second, fifth, third);
142                 }
143         case MSGGET:
144                 return sys_msgget ((key_t) first, second);
145         case MSGCTL:
146                 return sys_msgctl (first, second, (struct msqid_ds *) ptr);
147
148         case SHMAT:
149                 switch (version) {
150                 default: {
151                         ulong raddr;
152                         ret = do_shmat (first, (char *) ptr, second, &raddr);
153                         if (ret)
154                                 return ret;
155                         return put_user (raddr, (ulong *) third);
156                 }
157                 case 1: /* iBCS2 emulator entry point */
158                         if (!segment_eq(get_fs(), get_ds()))
159                                 return -EINVAL;
160                         return do_shmat (first, (char *) ptr, second, (ulong *) third);
161                 }
162         case SHMDT:
163                 return sys_shmdt ((char *)ptr);
164         case SHMGET:
165                 return sys_shmget (first, second, third);
166         case SHMCTL:
167                 return sys_shmctl (first, second,
168                                    (struct shmid_ds *) ptr);
169         default:
170                 return -ENOSYS;
171         }
172 }
173
174 long sys_sigaction(int sig, const struct old_sigaction __user *act,
175                          struct old_sigaction __user *oact)
176 {
177         struct k_sigaction new_ka, old_ka;
178         int ret;
179
180         if (act) {
181                 old_sigset_t mask;
182                 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
183                     __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
184                     __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
185                         return -EFAULT;
186                 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
187                 __get_user(mask, &act->sa_mask);
188                 siginitset(&new_ka.sa.sa_mask, mask);
189         }
190
191         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
192
193         if (!ret && oact) {
194                 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
195                     __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
196                     __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
197                         return -EFAULT;
198                 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
199                 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
200         }
201
202         return ret;
203 }