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