Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / arch / sparc64 / kernel / sys_sparc32.c
1 /* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
2  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
3  *
4  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
6  *
7  * These routines maintain argument size conversion between 32bit and 64bit
8  * environment.
9  */
10
11 #include <linux/config.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/capability.h>
15 #include <linux/fs.h> 
16 #include <linux/mm.h> 
17 #include <linux/file.h> 
18 #include <linux/signal.h>
19 #include <linux/resource.h>
20 #include <linux/times.h>
21 #include <linux/utsname.h>
22 #include <linux/smp.h>
23 #include <linux/smp_lock.h>
24 #include <linux/sem.h>
25 #include <linux/msg.h>
26 #include <linux/shm.h>
27 #include <linux/slab.h>
28 #include <linux/uio.h>
29 #include <linux/nfs_fs.h>
30 #include <linux/quota.h>
31 #include <linux/module.h>
32 #include <linux/sunrpc/svc.h>
33 #include <linux/nfsd/nfsd.h>
34 #include <linux/nfsd/cache.h>
35 #include <linux/nfsd/xdr.h>
36 #include <linux/nfsd/syscall.h>
37 #include <linux/poll.h>
38 #include <linux/personality.h>
39 #include <linux/stat.h>
40 #include <linux/filter.h>
41 #include <linux/highmem.h>
42 #include <linux/highuid.h>
43 #include <linux/mman.h>
44 #include <linux/ipv6.h>
45 #include <linux/in.h>
46 #include <linux/icmpv6.h>
47 #include <linux/syscalls.h>
48 #include <linux/sysctl.h>
49 #include <linux/binfmts.h>
50 #include <linux/dnotify.h>
51 #include <linux/security.h>
52 #include <linux/compat.h>
53 #include <linux/vfs.h>
54 #include <linux/netfilter_ipv4/ip_tables.h>
55 #include <linux/ptrace.h>
56 #include <linux/highuid.h>
57
58 #include <asm/types.h>
59 #include <asm/ipc.h>
60 #include <asm/uaccess.h>
61 #include <asm/fpumacro.h>
62 #include <asm/semaphore.h>
63 #include <asm/mmu_context.h>
64 #include <asm/a.out.h>
65
66 asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
67 {
68         return sys_chown(filename, low2highuid(user), low2highgid(group));
69 }
70
71 asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
72 {
73         return sys_lchown(filename, low2highuid(user), low2highgid(group));
74 }
75
76 asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
77 {
78         return sys_fchown(fd, low2highuid(user), low2highgid(group));
79 }
80
81 asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
82 {
83         return sys_setregid(low2highgid(rgid), low2highgid(egid));
84 }
85
86 asmlinkage long sys32_setgid16(u16 gid)
87 {
88         return sys_setgid((gid_t)gid);
89 }
90
91 asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
92 {
93         return sys_setreuid(low2highuid(ruid), low2highuid(euid));
94 }
95
96 asmlinkage long sys32_setuid16(u16 uid)
97 {
98         return sys_setuid((uid_t)uid);
99 }
100
101 asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
102 {
103         return sys_setresuid(low2highuid(ruid), low2highuid(euid),
104                 low2highuid(suid));
105 }
106
107 asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid)
108 {
109         int retval;
110
111         if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
112             !(retval = put_user(high2lowuid(current->euid), euid)))
113                 retval = put_user(high2lowuid(current->suid), suid);
114
115         return retval;
116 }
117
118 asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
119 {
120         return sys_setresgid(low2highgid(rgid), low2highgid(egid),
121                 low2highgid(sgid));
122 }
123
124 asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid)
125 {
126         int retval;
127
128         if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
129             !(retval = put_user(high2lowgid(current->egid), egid)))
130                 retval = put_user(high2lowgid(current->sgid), sgid);
131
132         return retval;
133 }
134
135 asmlinkage long sys32_setfsuid16(u16 uid)
136 {
137         return sys_setfsuid((uid_t)uid);
138 }
139
140 asmlinkage long sys32_setfsgid16(u16 gid)
141 {
142         return sys_setfsgid((gid_t)gid);
143 }
144
145 static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
146 {
147         int i;
148         u16 group;
149
150         for (i = 0; i < group_info->ngroups; i++) {
151                 group = (u16)GROUP_AT(group_info, i);
152                 if (put_user(group, grouplist+i))
153                         return -EFAULT;
154         }
155
156         return 0;
157 }
158
159 static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
160 {
161         int i;
162         u16 group;
163
164         for (i = 0; i < group_info->ngroups; i++) {
165                 if (get_user(group, grouplist+i))
166                         return  -EFAULT;
167                 GROUP_AT(group_info, i) = (gid_t)group;
168         }
169
170         return 0;
171 }
172
173 asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
174 {
175         int i;
176
177         if (gidsetsize < 0)
178                 return -EINVAL;
179
180         get_group_info(current->group_info);
181         i = current->group_info->ngroups;
182         if (gidsetsize) {
183                 if (i > gidsetsize) {
184                         i = -EINVAL;
185                         goto out;
186                 }
187                 if (groups16_to_user(grouplist, current->group_info)) {
188                         i = -EFAULT;
189                         goto out;
190                 }
191         }
192 out:
193         put_group_info(current->group_info);
194         return i;
195 }
196
197 asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
198 {
199         struct group_info *group_info;
200         int retval;
201
202         if (!capable(CAP_SETGID))
203                 return -EPERM;
204         if ((unsigned)gidsetsize > NGROUPS_MAX)
205                 return -EINVAL;
206
207         group_info = groups_alloc(gidsetsize);
208         if (!group_info)
209                 return -ENOMEM;
210         retval = groups16_from_user(group_info, grouplist);
211         if (retval) {
212                 put_group_info(group_info);
213                 return retval;
214         }
215
216         retval = set_current_groups(group_info);
217         put_group_info(group_info);
218
219         return retval;
220 }
221
222 asmlinkage long sys32_getuid16(void)
223 {
224         return high2lowuid(current->uid);
225 }
226
227 asmlinkage long sys32_geteuid16(void)
228 {
229         return high2lowuid(current->euid);
230 }
231
232 asmlinkage long sys32_getgid16(void)
233 {
234         return high2lowgid(current->gid);
235 }
236
237 asmlinkage long sys32_getegid16(void)
238 {
239         return high2lowgid(current->egid);
240 }
241
242 /* 32-bit timeval and related flotsam.  */
243
244 static long get_tv32(struct timeval *o, struct compat_timeval __user *i)
245 {
246         return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
247                 (__get_user(o->tv_sec, &i->tv_sec) |
248                  __get_user(o->tv_usec, &i->tv_usec)));
249 }
250
251 static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
252 {
253         return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
254                 (__put_user(i->tv_sec, &o->tv_sec) |
255                  __put_user(i->tv_usec, &o->tv_usec)));
256 }
257
258 #ifdef CONFIG_SYSVIPC                                                        
259 asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
260 {
261         int version;
262
263         version = call >> 16; /* hack for backward compatibility */
264         call &= 0xffff;
265
266         switch (call) {
267         case SEMTIMEDOP:
268                 if (fifth)
269                         /* sign extend semid */
270                         return compat_sys_semtimedop((int)first,
271                                                      compat_ptr(ptr), second,
272                                                      compat_ptr(fifth));
273                 /* else fall through for normal semop() */
274         case SEMOP:
275                 /* struct sembuf is the same on 32 and 64bit :)) */
276                 /* sign extend semid */
277                 return sys_semtimedop((int)first, compat_ptr(ptr), second,
278                                       NULL);
279         case SEMGET:
280                 /* sign extend key, nsems */
281                 return sys_semget((int)first, (int)second, third);
282         case SEMCTL:
283                 /* sign extend semid, semnum */
284                 return compat_sys_semctl((int)first, (int)second, third,
285                                          compat_ptr(ptr));
286
287         case MSGSND:
288                 /* sign extend msqid */
289                 return compat_sys_msgsnd((int)first, (int)second, third,
290                                          compat_ptr(ptr));
291         case MSGRCV:
292                 /* sign extend msqid, msgtyp */
293                 return compat_sys_msgrcv((int)first, second, (int)fifth,
294                                          third, version, compat_ptr(ptr));
295         case MSGGET:
296                 /* sign extend key */
297                 return sys_msgget((int)first, second);
298         case MSGCTL:
299                 /* sign extend msqid */
300                 return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
301
302         case SHMAT:
303                 /* sign extend shmid */
304                 return compat_sys_shmat((int)first, second, third, version,
305                                         compat_ptr(ptr));
306         case SHMDT:
307                 return sys_shmdt(compat_ptr(ptr));
308         case SHMGET:
309                 /* sign extend key_t */
310                 return sys_shmget((int)first, second, third);
311         case SHMCTL:
312                 /* sign extend shmid */
313                 return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
314
315         default:
316                 return -ENOSYS;
317         };
318
319         return -ENOSYS;
320 }
321 #endif
322
323 asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
324 {
325         if ((int)high < 0)
326                 return -EINVAL;
327         else
328                 return sys_truncate(path, (high << 32) | low);
329 }
330
331 asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
332 {
333         if ((int)high < 0)
334                 return -EINVAL;
335         else
336                 return sys_ftruncate(fd, (high << 32) | low);
337 }
338
339 int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
340 {
341         int err;
342
343         if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
344             !old_valid_dev(stat->rdev))
345                 return -EOVERFLOW;
346
347         err  = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
348         err |= put_user(stat->ino, &statbuf->st_ino);
349         err |= put_user(stat->mode, &statbuf->st_mode);
350         err |= put_user(stat->nlink, &statbuf->st_nlink);
351         err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
352         err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
353         err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
354         err |= put_user(stat->size, &statbuf->st_size);
355         err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
356         err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
357         err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
358         err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
359         err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
360         err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
361         err |= put_user(stat->blksize, &statbuf->st_blksize);
362         err |= put_user(stat->blocks, &statbuf->st_blocks);
363         err |= put_user(0, &statbuf->__unused4[0]);
364         err |= put_user(0, &statbuf->__unused4[1]);
365
366         return err;
367 }
368
369 int cp_compat_stat64(struct kstat *stat, struct compat_stat64 __user *statbuf)
370 {
371         int err;
372
373         err  = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev);
374         err |= put_user(stat->ino, &statbuf->st_ino);
375         err |= put_user(stat->mode, &statbuf->st_mode);
376         err |= put_user(stat->nlink, &statbuf->st_nlink);
377         err |= put_user(stat->uid, &statbuf->st_uid);
378         err |= put_user(stat->gid, &statbuf->st_gid);
379         err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
380         err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
381         err |= put_user(stat->size, &statbuf->st_size);
382         err |= put_user(stat->blksize, &statbuf->st_blksize);
383         err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]);
384         err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]);
385         err |= put_user(stat->blocks, &statbuf->st_blocks);
386         err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
387         err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
388         err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
389         err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
390         err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
391         err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
392         err |= put_user(0, &statbuf->__unused4);
393         err |= put_user(0, &statbuf->__unused5);
394
395         return err;
396 }
397
398 asmlinkage long compat_sys_stat64(char __user * filename,
399                 struct compat_stat64 __user *statbuf)
400 {
401         struct kstat stat;
402         int error = vfs_stat(filename, &stat);
403
404         if (!error)
405                 error = cp_compat_stat64(&stat, statbuf);
406         return error;
407 }
408
409 asmlinkage long compat_sys_lstat64(char __user * filename,
410                 struct compat_stat64 __user *statbuf)
411 {
412         struct kstat stat;
413         int error = vfs_lstat(filename, &stat);
414
415         if (!error)
416                 error = cp_compat_stat64(&stat, statbuf);
417         return error;
418 }
419
420 asmlinkage long compat_sys_fstat64(unsigned int fd,
421                 struct compat_stat64 __user * statbuf)
422 {
423         struct kstat stat;
424         int error = vfs_fstat(fd, &stat);
425
426         if (!error)
427                 error = cp_compat_stat64(&stat, statbuf);
428         return error;
429 }
430
431 asmlinkage long compat_sys_fstatat64(unsigned int dfd, char __user *filename,
432                 struct compat_stat64 __user * statbuf, int flag)
433 {
434         struct kstat stat;
435         int error = -EINVAL;
436
437         if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
438                 goto out;
439
440         if (flag & AT_SYMLINK_NOFOLLOW)
441                 error = vfs_lstat_fd(dfd, filename, &stat);
442         else
443                 error = vfs_stat_fd(dfd, filename, &stat);
444
445         if (!error)
446                 error = cp_compat_stat64(&stat, statbuf);
447
448 out:
449         return error;
450 }
451
452 asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
453 {
454         return sys_sysfs(option, arg1, arg2);
455 }
456
457 struct sysinfo32 {
458         s32 uptime;
459         u32 loads[3];
460         u32 totalram;
461         u32 freeram;
462         u32 sharedram;
463         u32 bufferram;
464         u32 totalswap;
465         u32 freeswap;
466         unsigned short procs;
467         unsigned short pad;
468         u32 totalhigh;
469         u32 freehigh;
470         u32 mem_unit;
471         char _f[20-2*sizeof(int)-sizeof(int)];
472 };
473
474 asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
475 {
476         struct sysinfo s;
477         int ret, err;
478         int bitcount = 0;
479         mm_segment_t old_fs = get_fs ();
480         
481         set_fs(KERNEL_DS);
482         ret = sys_sysinfo((struct sysinfo __user *) &s);
483         set_fs(old_fs);
484         /* Check to see if any memory value is too large for 32-bit and
485          * scale down if needed.
486          */
487         if ((s.totalram >> 32) || (s.totalswap >> 32)) {
488                 while (s.mem_unit < PAGE_SIZE) {
489                         s.mem_unit <<= 1;
490                         bitcount++;
491                 }
492                 s.totalram >>= bitcount;
493                 s.freeram >>= bitcount;
494                 s.sharedram >>= bitcount;
495                 s.bufferram >>= bitcount;
496                 s.totalswap >>= bitcount;
497                 s.freeswap >>= bitcount;
498                 s.totalhigh >>= bitcount;
499                 s.freehigh >>= bitcount;
500         }
501
502         err = put_user (s.uptime, &info->uptime);
503         err |= __put_user (s.loads[0], &info->loads[0]);
504         err |= __put_user (s.loads[1], &info->loads[1]);
505         err |= __put_user (s.loads[2], &info->loads[2]);
506         err |= __put_user (s.totalram, &info->totalram);
507         err |= __put_user (s.freeram, &info->freeram);
508         err |= __put_user (s.sharedram, &info->sharedram);
509         err |= __put_user (s.bufferram, &info->bufferram);
510         err |= __put_user (s.totalswap, &info->totalswap);
511         err |= __put_user (s.freeswap, &info->freeswap);
512         err |= __put_user (s.procs, &info->procs);
513         err |= __put_user (s.totalhigh, &info->totalhigh);
514         err |= __put_user (s.freehigh, &info->freehigh);
515         err |= __put_user (s.mem_unit, &info->mem_unit);
516         if (err)
517                 return -EFAULT;
518         return ret;
519 }
520
521 asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
522 {
523         struct timespec t;
524         int ret;
525         mm_segment_t old_fs = get_fs ();
526         
527         set_fs (KERNEL_DS);
528         ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
529         set_fs (old_fs);
530         if (put_compat_timespec(&t, interval))
531                 return -EFAULT;
532         return ret;
533 }
534
535 asmlinkage long compat_sys_rt_sigprocmask(int how,
536                                           compat_sigset_t __user *set,
537                                           compat_sigset_t __user *oset,
538                                           compat_size_t sigsetsize)
539 {
540         sigset_t s;
541         compat_sigset_t s32;
542         int ret;
543         mm_segment_t old_fs = get_fs();
544         
545         if (set) {
546                 if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
547                         return -EFAULT;
548                 switch (_NSIG_WORDS) {
549                 case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
550                 case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
551                 case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
552                 case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
553                 }
554         }
555         set_fs (KERNEL_DS);
556         ret = sys_rt_sigprocmask(how,
557                                  set ? (sigset_t __user *) &s : NULL,
558                                  oset ? (sigset_t __user *) &s : NULL,
559                                  sigsetsize);
560         set_fs (old_fs);
561         if (ret) return ret;
562         if (oset) {
563                 switch (_NSIG_WORDS) {
564                 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
565                 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
566                 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
567                 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
568                 }
569                 if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
570                         return -EFAULT;
571         }
572         return 0;
573 }
574
575 asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
576                                     compat_size_t sigsetsize)
577 {
578         sigset_t s;
579         compat_sigset_t s32;
580         int ret;
581         mm_segment_t old_fs = get_fs();
582                 
583         set_fs (KERNEL_DS);
584         ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
585         set_fs (old_fs);
586         if (!ret) {
587                 switch (_NSIG_WORDS) {
588                 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
589                 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
590                 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
591                 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
592                 }
593                 if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
594                         return -EFAULT;
595         }
596         return ret;
597 }
598
599 asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
600                                            struct compat_siginfo __user *uinfo)
601 {
602         siginfo_t info;
603         int ret;
604         mm_segment_t old_fs = get_fs();
605         
606         if (copy_siginfo_from_user32(&info, uinfo))
607                 return -EFAULT;
608
609         set_fs (KERNEL_DS);
610         ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
611         set_fs (old_fs);
612         return ret;
613 }
614
615 asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act,
616                                      struct old_sigaction32 __user *oact)
617 {
618         struct k_sigaction new_ka, old_ka;
619         int ret;
620
621         if (sig < 0) {
622                 set_thread_flag(TIF_NEWSIGNALS);
623                 sig = -sig;
624         }
625
626         if (act) {
627                 compat_old_sigset_t mask;
628                 u32 u_handler, u_restorer;
629                 
630                 ret = get_user(u_handler, &act->sa_handler);
631                 new_ka.sa.sa_handler =  compat_ptr(u_handler);
632                 ret |= __get_user(u_restorer, &act->sa_restorer);
633                 new_ka.sa.sa_restorer = compat_ptr(u_restorer);
634                 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
635                 ret |= __get_user(mask, &act->sa_mask);
636                 if (ret)
637                         return ret;
638                 new_ka.ka_restorer = NULL;
639                 siginitset(&new_ka.sa.sa_mask, mask);
640         }
641
642         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
643
644         if (!ret && oact) {
645                 ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
646                 ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
647                 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
648                 ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
649         }
650
651         return ret;
652 }
653
654 asmlinkage long compat_sys_rt_sigaction(int sig,
655                                         struct sigaction32 __user *act,
656                                         struct sigaction32 __user *oact,
657                                         void __user *restorer,
658                                         compat_size_t sigsetsize)
659 {
660         struct k_sigaction new_ka, old_ka;
661         int ret;
662         compat_sigset_t set32;
663
664         /* XXX: Don't preclude handling different sized sigset_t's.  */
665         if (sigsetsize != sizeof(compat_sigset_t))
666                 return -EINVAL;
667
668         /* All tasks which use RT signals (effectively) use
669          * new style signals.
670          */
671         set_thread_flag(TIF_NEWSIGNALS);
672
673         if (act) {
674                 u32 u_handler, u_restorer;
675
676                 new_ka.ka_restorer = restorer;
677                 ret = get_user(u_handler, &act->sa_handler);
678                 new_ka.sa.sa_handler =  compat_ptr(u_handler);
679                 ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
680                 switch (_NSIG_WORDS) {
681                 case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
682                 case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
683                 case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
684                 case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
685                 }
686                 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
687                 ret |= __get_user(u_restorer, &act->sa_restorer);
688                 new_ka.sa.sa_restorer = compat_ptr(u_restorer);
689                 if (ret)
690                         return -EFAULT;
691         }
692
693         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
694
695         if (!ret && oact) {
696                 switch (_NSIG_WORDS) {
697                 case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
698                 case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
699                 case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
700                 case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
701                 }
702                 ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
703                 ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
704                 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
705                 ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
706                 if (ret)
707                         ret = -EFAULT;
708         }
709
710         return ret;
711 }
712
713 /*
714  * sparc32_execve() executes a new program after the asm stub has set
715  * things up for us.  This should basically do what I want it to.
716  */
717 asmlinkage long sparc32_execve(struct pt_regs *regs)
718 {
719         int error, base = 0;
720         char *filename;
721
722         /* User register window flush is done by entry.S */
723
724         /* Check for indirect call. */
725         if ((u32)regs->u_regs[UREG_G1] == 0)
726                 base = 1;
727
728         filename = getname(compat_ptr(regs->u_regs[base + UREG_I0]));
729         error = PTR_ERR(filename);
730         if (IS_ERR(filename))
731                 goto out;
732
733         error = compat_do_execve(filename,
734                                  compat_ptr(regs->u_regs[base + UREG_I1]),
735                                  compat_ptr(regs->u_regs[base + UREG_I2]), regs);
736
737         putname(filename);
738
739         if (!error) {
740                 fprs_write(0);
741                 current_thread_info()->xfsr[0] = 0;
742                 current_thread_info()->fpsaved[0] = 0;
743                 regs->tstate &= ~TSTATE_PEF;
744                 task_lock(current);
745                 current->ptrace &= ~PT_DTRACE;
746                 task_unlock(current);
747         }
748 out:
749         return error;
750 }
751
752 #ifdef CONFIG_MODULES
753
754 asmlinkage long sys32_init_module(void __user *umod, u32 len,
755                                   const char __user *uargs)
756 {
757         return sys_init_module(umod, len, uargs);
758 }
759
760 asmlinkage long sys32_delete_module(const char __user *name_user,
761                                     unsigned int flags)
762 {
763         return sys_delete_module(name_user, flags);
764 }
765
766 #else /* CONFIG_MODULES */
767
768 asmlinkage long sys32_init_module(const char __user *name_user,
769                                   struct module __user *mod_user)
770 {
771         return -ENOSYS;
772 }
773
774 asmlinkage long sys32_delete_module(const char __user *name_user)
775 {
776         return -ENOSYS;
777 }
778
779 #endif  /* CONFIG_MODULES */
780
781 /* Translations due to time_t size differences.  Which affects all
782    sorts of things, like timeval and itimerval.  */
783
784 extern struct timezone sys_tz;
785
786 asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
787                                    struct timezone __user *tz)
788 {
789         if (tv) {
790                 struct timeval ktv;
791                 do_gettimeofday(&ktv);
792                 if (put_tv32(tv, &ktv))
793                         return -EFAULT;
794         }
795         if (tz) {
796                 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
797                         return -EFAULT;
798         }
799         return 0;
800 }
801
802 static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
803 {
804         long usec;
805
806         if (!access_ok(VERIFY_READ, i, sizeof(*i)))
807                 return -EFAULT;
808         if (__get_user(o->tv_sec, &i->tv_sec))
809                 return -EFAULT;
810         if (__get_user(usec, &i->tv_usec))
811                 return -EFAULT;
812         o->tv_nsec = usec * 1000;
813         return 0;
814 }
815
816 asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
817                                    struct timezone __user *tz)
818 {
819         struct timespec kts;
820         struct timezone ktz;
821
822         if (tv) {
823                 if (get_ts32(&kts, tv))
824                         return -EFAULT;
825         }
826         if (tz) {
827                 if (copy_from_user(&ktz, tz, sizeof(ktz)))
828                         return -EFAULT;
829         }
830
831         return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
832 }
833
834 asmlinkage long sys32_utimes(char __user *filename,
835                              struct compat_timeval __user *tvs)
836 {
837         struct timeval ktvs[2];
838
839         if (tvs) {
840                 if (get_tv32(&ktvs[0], tvs) ||
841                     get_tv32(&ktvs[1], 1+tvs))
842                         return -EFAULT;
843         }
844
845         return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL));
846 }
847
848 /* These are here just in case some old sparc32 binary calls it. */
849 asmlinkage long sys32_pause(void)
850 {
851         current->state = TASK_INTERRUPTIBLE;
852         schedule();
853         return -ERESTARTNOHAND;
854 }
855
856 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
857                                         char __user *ubuf,
858                                         compat_size_t count,
859                                         unsigned long poshi,
860                                         unsigned long poslo)
861 {
862         return sys_pread64(fd, ubuf, count, (poshi << 32) | poslo);
863 }
864
865 asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd,
866                                          char __user *ubuf,
867                                          compat_size_t count,
868                                          unsigned long poshi,
869                                          unsigned long poslo)
870 {
871         return sys_pwrite64(fd, ubuf, count, (poshi << 32) | poslo);
872 }
873
874 asmlinkage long compat_sys_readahead(int fd,
875                                      unsigned long offhi,
876                                      unsigned long offlo,
877                                      compat_size_t count)
878 {
879         return sys_readahead(fd, (offhi << 32) | offlo, count);
880 }
881
882 long compat_sys_fadvise64(int fd,
883                           unsigned long offhi,
884                           unsigned long offlo,
885                           compat_size_t len, int advice)
886 {
887         return sys_fadvise64_64(fd, (offhi << 32) | offlo, len, advice);
888 }
889
890 long compat_sys_fadvise64_64(int fd,
891                              unsigned long offhi, unsigned long offlo,
892                              unsigned long lenhi, unsigned long lenlo,
893                              int advice)
894 {
895         return sys_fadvise64_64(fd,
896                                 (offhi << 32) | offlo,
897                                 (lenhi << 32) | lenlo,
898                                 advice);
899 }
900
901 asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
902                                     compat_off_t __user *offset,
903                                     compat_size_t count)
904 {
905         mm_segment_t old_fs = get_fs();
906         int ret;
907         off_t of;
908         
909         if (offset && get_user(of, offset))
910                 return -EFAULT;
911                 
912         set_fs(KERNEL_DS);
913         ret = sys_sendfile(out_fd, in_fd,
914                            offset ? (off_t __user *) &of : NULL,
915                            count);
916         set_fs(old_fs);
917         
918         if (offset && put_user(of, offset))
919                 return -EFAULT;
920                 
921         return ret;
922 }
923
924 asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd,
925                                       compat_loff_t __user *offset,
926                                       compat_size_t count)
927 {
928         mm_segment_t old_fs = get_fs();
929         int ret;
930         loff_t lof;
931         
932         if (offset && get_user(lof, offset))
933                 return -EFAULT;
934                 
935         set_fs(KERNEL_DS);
936         ret = sys_sendfile64(out_fd, in_fd,
937                              offset ? (loff_t __user *) &lof : NULL,
938                              count);
939         set_fs(old_fs);
940         
941         if (offset && put_user(lof, offset))
942                 return -EFAULT;
943                 
944         return ret;
945 }
946
947 /* This is just a version for 32-bit applications which does
948  * not force O_LARGEFILE on.
949  */
950
951 asmlinkage long sparc32_open(const char __user *filename,
952                              int flags, int mode)
953 {
954         return do_sys_open(AT_FDCWD, filename, flags, mode);
955 }
956
957 extern unsigned long do_mremap(unsigned long addr,
958         unsigned long old_len, unsigned long new_len,
959         unsigned long flags, unsigned long new_addr);
960                 
961 asmlinkage unsigned long sys32_mremap(unsigned long addr,
962         unsigned long old_len, unsigned long new_len,
963         unsigned long flags, u32 __new_addr)
964 {
965         struct vm_area_struct *vma;
966         unsigned long ret = -EINVAL;
967         unsigned long new_addr = __new_addr;
968
969         if (old_len > STACK_TOP32 || new_len > STACK_TOP32)
970                 goto out;
971         if (addr > STACK_TOP32 - old_len)
972                 goto out;
973         down_write(&current->mm->mmap_sem);
974         if (flags & MREMAP_FIXED) {
975                 if (new_addr > STACK_TOP32 - new_len)
976                         goto out_sem;
977         } else if (addr > STACK_TOP32 - new_len) {
978                 unsigned long map_flags = 0;
979                 struct file *file = NULL;
980
981                 ret = -ENOMEM;
982                 if (!(flags & MREMAP_MAYMOVE))
983                         goto out_sem;
984
985                 vma = find_vma(current->mm, addr);
986                 if (vma) {
987                         if (vma->vm_flags & VM_SHARED)
988                                 map_flags |= MAP_SHARED;
989                         file = vma->vm_file;
990                 }
991
992                 /* MREMAP_FIXED checked above. */
993                 new_addr = get_unmapped_area(file, addr, new_len,
994                                     vma ? vma->vm_pgoff : 0,
995                                     map_flags);
996                 ret = new_addr;
997                 if (new_addr & ~PAGE_MASK)
998                         goto out_sem;
999                 flags |= MREMAP_FIXED;
1000         }
1001         ret = do_mremap(addr, old_len, new_len, flags, new_addr);
1002 out_sem:
1003         up_write(&current->mm->mmap_sem);
1004 out:
1005         return ret;       
1006 }
1007
1008 struct __sysctl_args32 {
1009         u32 name;
1010         int nlen;
1011         u32 oldval;
1012         u32 oldlenp;
1013         u32 newval;
1014         u32 newlen;
1015         u32 __unused[4];
1016 };
1017
1018 asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
1019 {
1020 #ifndef CONFIG_SYSCTL
1021         return -ENOSYS;
1022 #else
1023         struct __sysctl_args32 tmp;
1024         int error;
1025         size_t oldlen, __user *oldlenp = NULL;
1026         unsigned long addr = (((unsigned long)&args->__unused[0]) + 7UL) & ~7UL;
1027
1028         if (copy_from_user(&tmp, args, sizeof(tmp)))
1029                 return -EFAULT;
1030
1031         if (tmp.oldval && tmp.oldlenp) {
1032                 /* Duh, this is ugly and might not work if sysctl_args
1033                    is in read-only memory, but do_sysctl does indirectly
1034                    a lot of uaccess in both directions and we'd have to
1035                    basically copy the whole sysctl.c here, and
1036                    glibc's __sysctl uses rw memory for the structure
1037                    anyway.  */
1038                 if (get_user(oldlen, (u32 __user *)(unsigned long)tmp.oldlenp) ||
1039                     put_user(oldlen, (size_t __user *)addr))
1040                         return -EFAULT;
1041                 oldlenp = (size_t __user *)addr;
1042         }
1043
1044         lock_kernel();
1045         error = do_sysctl((int __user *)(unsigned long) tmp.name,
1046                           tmp.nlen,
1047                           (void __user *)(unsigned long) tmp.oldval,
1048                           oldlenp,
1049                           (void __user *)(unsigned long) tmp.newval,
1050                           tmp.newlen);
1051         unlock_kernel();
1052         if (oldlenp) {
1053                 if (!error) {
1054                         if (get_user(oldlen, (size_t __user *)addr) ||
1055                             put_user(oldlen, (u32 __user *)(unsigned long) tmp.oldlenp))
1056                                 error = -EFAULT;
1057                 }
1058                 if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
1059                         error = -EFAULT;
1060         }
1061         return error;
1062 #endif
1063 }
1064
1065 long sys32_lookup_dcookie(unsigned long cookie_high,
1066                           unsigned long cookie_low,
1067                           char __user *buf, size_t len)
1068 {
1069         return sys_lookup_dcookie((cookie_high << 32) | cookie_low,
1070                                   buf, len);
1071 }