xref: /linux/arch/parisc/kernel/sys_parisc32.c (revision 4bedea94545165364618d403d03b61d797acba0b)
1 /*
2  * sys_parisc32.c: Conversion between 32bit and 64bit native syscalls.
3  *
4  * Copyright (C) 2000-2001 Hewlett Packard Company
5  * Copyright (C) 2000 John Marvin
6  * Copyright (C) 2001 Matthew Wilcox
7  *
8  * These routines maintain argument size conversion between 32bit and 64bit
9  * environment. Based heavily on sys_ia32.c and sys_sparc32.c.
10  */
11 
12 #include <linux/config.h>
13 #include <linux/compat.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/fs.h>
17 #include <linux/mm.h>
18 #include <linux/file.h>
19 #include <linux/signal.h>
20 #include <linux/resource.h>
21 #include <linux/times.h>
22 #include <linux/utsname.h>
23 #include <linux/time.h>
24 #include <linux/timex.h>
25 #include <linux/smp.h>
26 #include <linux/smp_lock.h>
27 #include <linux/sem.h>
28 #include <linux/msg.h>
29 #include <linux/shm.h>
30 #include <linux/slab.h>
31 #include <linux/uio.h>
32 #include <linux/nfs_fs.h>
33 #include <linux/ncp_fs.h>
34 #include <linux/sunrpc/svc.h>
35 #include <linux/nfsd/nfsd.h>
36 #include <linux/nfsd/cache.h>
37 #include <linux/nfsd/xdr.h>
38 #include <linux/nfsd/syscall.h>
39 #include <linux/poll.h>
40 #include <linux/personality.h>
41 #include <linux/stat.h>
42 #include <linux/highmem.h>
43 #include <linux/highuid.h>
44 #include <linux/mman.h>
45 #include <linux/binfmts.h>
46 #include <linux/namei.h>
47 #include <linux/vfs.h>
48 #include <linux/ptrace.h>
49 #include <linux/swap.h>
50 #include <linux/syscalls.h>
51 
52 #include <asm/types.h>
53 #include <asm/uaccess.h>
54 #include <asm/semaphore.h>
55 #include <asm/mmu_context.h>
56 
57 #include "sys32.h"
58 
59 #undef DEBUG
60 
61 #ifdef DEBUG
62 #define DBG(x)	printk x
63 #else
64 #define DBG(x)
65 #endif
66 
67 /*
68  * sys32_execve() executes a new program.
69  */
70 
71 asmlinkage int sys32_execve(struct pt_regs *regs)
72 {
73 	int error;
74 	char *filename;
75 
76 	DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
77 	filename = getname((const char __user *) regs->gr[26]);
78 	error = PTR_ERR(filename);
79 	if (IS_ERR(filename))
80 		goto out;
81 	error = compat_do_execve(filename, compat_ptr(regs->gr[25]),
82 				 compat_ptr(regs->gr[24]), regs);
83 	if (error == 0) {
84 		task_lock(current);
85 		current->ptrace &= ~PT_DTRACE;
86 		task_unlock(current);
87 	}
88 	putname(filename);
89 out:
90 
91 	return error;
92 }
93 
94 asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
95 	int r22, int r21, int r20)
96 {
97     printk(KERN_ERR "%s(%d): Unimplemented 32 on 64 syscall #%d!\n",
98     	current->comm, current->pid, r20);
99     return -ENOSYS;
100 }
101 
102 #ifdef CONFIG_SYSCTL
103 
104 struct __sysctl_args32 {
105 	u32 name;
106 	int nlen;
107 	u32 oldval;
108 	u32 oldlenp;
109 	u32 newval;
110 	u32 newlen;
111 	u32 __unused[4];
112 };
113 
114 asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
115 {
116 	struct __sysctl_args32 tmp;
117 	int error;
118 	unsigned int oldlen32;
119 	size_t oldlen, *oldlenp = NULL;
120 	unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7;
121 	extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
122 	       void *newval, size_t newlen);
123 
124 	DBG(("sysctl32(%p)\n", args));
125 
126 	if (copy_from_user(&tmp, args, sizeof(tmp)))
127 		return -EFAULT;
128 
129 	if (tmp.oldval && tmp.oldlenp) {
130 		/* Duh, this is ugly and might not work if sysctl_args
131 		   is in read-only memory, but do_sysctl does indirectly
132 		   a lot of uaccess in both directions and we'd have to
133 		   basically copy the whole sysctl.c here, and
134 		   glibc's __sysctl uses rw memory for the structure
135 		   anyway.  */
136 		/* a possibly better hack than this, which will avoid the
137 		 * problem if the struct is read only, is to push the
138 		 * 'oldlen' value out to the user's stack instead. -PB
139 		 */
140 		if (get_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
141 			return -EFAULT;
142 		oldlen = oldlen32;
143 		if (put_user(oldlen, (size_t *)addr))
144 			return -EFAULT;
145 		oldlenp = (size_t *)addr;
146 	}
147 
148 	lock_kernel();
149 	error = do_sysctl((int *)(u64)tmp.name, tmp.nlen, (void *)(u64)tmp.oldval,
150 			  oldlenp, (void *)(u64)tmp.newval, tmp.newlen);
151 	unlock_kernel();
152 	if (oldlenp) {
153 		if (!error) {
154 			if (get_user(oldlen, (size_t *)addr)) {
155 				error = -EFAULT;
156 			} else {
157 				oldlen32 = oldlen;
158 				if (put_user(oldlen32, (u32 *)(u64)tmp.oldlenp))
159 					error = -EFAULT;
160 			}
161 		}
162 		if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused)))
163 			error = -EFAULT;
164 	}
165 	return error;
166 }
167 
168 #endif /* CONFIG_SYSCTL */
169 
170 asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
171 	struct compat_timespec __user *interval)
172 {
173 	struct timespec t;
174 	int ret;
175 
176 	KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t);
177 	if (put_compat_timespec(&t, interval))
178 		return -EFAULT;
179 	return ret;
180 }
181 
182 static int
183 put_compat_timeval(struct compat_timeval __user *u, struct timeval *t)
184 {
185 	struct compat_timeval t32;
186 	t32.tv_sec = t->tv_sec;
187 	t32.tv_usec = t->tv_usec;
188 	return copy_to_user(u, &t32, sizeof t32);
189 }
190 
191 static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
192 {
193 	long usec;
194 
195 	if (__get_user(o->tv_sec, &i->tv_sec))
196 		return -EFAULT;
197 	if (__get_user(usec, &i->tv_usec))
198 		return -EFAULT;
199 	o->tv_nsec = usec * 1000;
200 	return 0;
201 }
202 
203 asmlinkage int
204 sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
205 {
206     extern void do_gettimeofday(struct timeval *tv);
207 
208     if (tv) {
209 	    struct timeval ktv;
210 	    do_gettimeofday(&ktv);
211 	    if (put_compat_timeval(tv, &ktv))
212 		    return -EFAULT;
213     }
214     if (tz) {
215 	    extern struct timezone sys_tz;
216 	    if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
217 		    return -EFAULT;
218     }
219     return 0;
220 }
221 
222 asmlinkage
223 int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
224 {
225 	struct timespec kts;
226 	struct timezone ktz;
227 
228  	if (tv) {
229 		if (get_ts32(&kts, tv))
230 			return -EFAULT;
231 	}
232 	if (tz) {
233 		if (copy_from_user(&ktz, tz, sizeof(ktz)))
234 			return -EFAULT;
235 	}
236 
237 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
238 }
239 
240 int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
241 {
242 	int err;
243 
244 	if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
245 	    !new_valid_dev(stat->rdev))
246 		return -EOVERFLOW;
247 
248 	err  = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
249 	err |= put_user(stat->ino, &statbuf->st_ino);
250 	err |= put_user(stat->mode, &statbuf->st_mode);
251 	err |= put_user(stat->nlink, &statbuf->st_nlink);
252 	err |= put_user(0, &statbuf->st_reserved1);
253 	err |= put_user(0, &statbuf->st_reserved2);
254 	err |= put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);
255 	err |= put_user(stat->size, &statbuf->st_size);
256 	err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
257 	err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
258 	err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
259 	err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
260 	err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
261 	err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
262 	err |= put_user(stat->blksize, &statbuf->st_blksize);
263 	err |= put_user(stat->blocks, &statbuf->st_blocks);
264 	err |= put_user(0, &statbuf->__unused1);
265 	err |= put_user(0, &statbuf->__unused2);
266 	err |= put_user(0, &statbuf->__unused3);
267 	err |= put_user(0, &statbuf->__unused4);
268 	err |= put_user(0, &statbuf->__unused5);
269 	err |= put_user(0, &statbuf->st_fstype); /* not avail */
270 	err |= put_user(0, &statbuf->st_realdev); /* not avail */
271 	err |= put_user(0, &statbuf->st_basemode); /* not avail */
272 	err |= put_user(0, &statbuf->st_spareshort);
273 	err |= put_user(stat->uid, &statbuf->st_uid);
274 	err |= put_user(stat->gid, &statbuf->st_gid);
275 	err |= put_user(0, &statbuf->st_spare4[0]);
276 	err |= put_user(0, &statbuf->st_spare4[1]);
277 	err |= put_user(0, &statbuf->st_spare4[2]);
278 
279 	return err;
280 }
281 
282 struct linux32_dirent {
283 	u32		d_ino;
284 	compat_off_t	d_off;
285 	u16		d_reclen;
286 	char		d_name[1];
287 };
288 
289 struct old_linux32_dirent {
290 	u32	d_ino;
291 	u32	d_offset;
292 	u16	d_namlen;
293 	char	d_name[1];
294 };
295 
296 struct getdents32_callback {
297 	struct linux32_dirent __user * current_dir;
298 	struct linux32_dirent __user * previous;
299 	int count;
300 	int error;
301 };
302 
303 struct readdir32_callback {
304 	struct old_linux32_dirent __user * dirent;
305 	int count;
306 };
307 
308 #define ROUND_UP(x,a)	((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
309 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
310 static int
311 filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
312 	   unsigned int d_type)
313 {
314 	struct linux32_dirent __user * dirent;
315 	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
316 	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
317 
318 	buf->error = -EINVAL;	/* only used if we fail.. */
319 	if (reclen > buf->count)
320 		return -EINVAL;
321 	dirent = buf->previous;
322 	if (dirent)
323 		put_user(offset, &dirent->d_off);
324 	dirent = buf->current_dir;
325 	buf->previous = dirent;
326 	put_user(ino, &dirent->d_ino);
327 	put_user(reclen, &dirent->d_reclen);
328 	copy_to_user(dirent->d_name, name, namlen);
329 	put_user(0, dirent->d_name + namlen);
330 	dirent = ((void __user *)dirent) + reclen;
331 	buf->current_dir = dirent;
332 	buf->count -= reclen;
333 	return 0;
334 }
335 
336 asmlinkage long
337 sys32_getdents (unsigned int fd, void __user * dirent, unsigned int count)
338 {
339 	struct file * file;
340 	struct linux32_dirent __user * lastdirent;
341 	struct getdents32_callback buf;
342 	int error;
343 
344 	error = -EBADF;
345 	file = fget(fd);
346 	if (!file)
347 		goto out;
348 
349 	buf.current_dir = (struct linux32_dirent __user *) dirent;
350 	buf.previous = NULL;
351 	buf.count = count;
352 	buf.error = 0;
353 
354 	error = vfs_readdir(file, filldir32, &buf);
355 	if (error < 0)
356 		goto out_putf;
357 	error = buf.error;
358 	lastdirent = buf.previous;
359 	if (lastdirent) {
360 		put_user(file->f_pos, &lastdirent->d_off);
361 		error = count - buf.count;
362 	}
363 
364 out_putf:
365 	fput(file);
366 out:
367 	return error;
368 }
369 
370 static int
371 fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
372 	      unsigned int d_type)
373 {
374 	struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
375 	struct old_linux32_dirent __user * dirent;
376 
377 	if (buf->count)
378 		return -EINVAL;
379 	buf->count++;
380 	dirent = buf->dirent;
381 	put_user(ino, &dirent->d_ino);
382 	put_user(offset, &dirent->d_offset);
383 	put_user(namlen, &dirent->d_namlen);
384 	copy_to_user(dirent->d_name, name, namlen);
385 	put_user(0, dirent->d_name + namlen);
386 	return 0;
387 }
388 
389 asmlinkage long
390 sys32_readdir (unsigned int fd, void __user * dirent, unsigned int count)
391 {
392 	int error;
393 	struct file * file;
394 	struct readdir32_callback buf;
395 
396 	error = -EBADF;
397 	file = fget(fd);
398 	if (!file)
399 		goto out;
400 
401 	buf.count = 0;
402 	buf.dirent = dirent;
403 
404 	error = vfs_readdir(file, fillonedir32, &buf);
405 	if (error >= 0)
406 		error = buf.count;
407 	fput(file);
408 out:
409 	return error;
410 }
411 
412 /*** copied from mips64 ***/
413 /*
414  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
415  * 64-bit unsigned longs.
416  */
417 
418 static inline int
419 get_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
420 {
421 	n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
422 	if (ufdset) {
423 		unsigned long odd;
424 
425 		if (!access_ok(VERIFY_WRITE, ufdset, n*sizeof(u32)))
426 			return -EFAULT;
427 
428 		odd = n & 1UL;
429 		n &= ~1UL;
430 		while (n) {
431 			unsigned long h, l;
432 			__get_user(l, ufdset);
433 			__get_user(h, ufdset+1);
434 			ufdset += 2;
435 			*fdset++ = h << 32 | l;
436 			n -= 2;
437 		}
438 		if (odd)
439 			__get_user(*fdset, ufdset);
440 	} else {
441 		/* Tricky, must clear full unsigned long in the
442 		 * kernel fdset at the end, this makes sure that
443 		 * actually happens.
444 		 */
445 		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
446 	}
447 	return 0;
448 }
449 
450 static inline void
451 set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
452 {
453 	unsigned long odd;
454 	n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
455 
456 	if (!ufdset)
457 		return;
458 
459 	odd = n & 1UL;
460 	n &= ~1UL;
461 	while (n) {
462 		unsigned long h, l;
463 		l = *fdset++;
464 		h = l >> 32;
465 		__put_user(l, ufdset);
466 		__put_user(h, ufdset+1);
467 		ufdset += 2;
468 		n -= 2;
469 	}
470 	if (odd)
471 		__put_user(*fdset, ufdset);
472 }
473 
474 struct msgbuf32 {
475     int mtype;
476     char mtext[1];
477 };
478 
479 asmlinkage long sys32_msgsnd(int msqid,
480 				struct msgbuf32 __user *umsgp32,
481 				size_t msgsz, int msgflg)
482 {
483 	struct msgbuf *mb;
484 	struct msgbuf32 mb32;
485 	int err;
486 
487 	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
488 		return -ENOMEM;
489 
490 	err = get_user(mb32.mtype, &umsgp32->mtype);
491 	mb->mtype = mb32.mtype;
492 	err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz);
493 
494 	if (err)
495 		err = -EFAULT;
496 	else
497 		KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg);
498 
499 	kfree(mb);
500 	return err;
501 }
502 
503 asmlinkage long sys32_msgrcv(int msqid,
504 				struct msgbuf32 __user *umsgp32,
505 				size_t msgsz, long msgtyp, int msgflg)
506 {
507 	struct msgbuf *mb;
508 	struct msgbuf32 mb32;
509 	int err, len;
510 
511 	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
512 		return -ENOMEM;
513 
514 	KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg);
515 
516 	if (err >= 0) {
517 		len = err;
518 		mb32.mtype = mb->mtype;
519 		err = put_user(mb32.mtype, &umsgp32->mtype);
520 		err |= copy_to_user(&umsgp32->mtext, mb->mtext, len);
521 		if (err)
522 			err = -EFAULT;
523 		else
524 			err = len;
525 	}
526 
527 	kfree(mb);
528 	return err;
529 }
530 
531 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
532 {
533         mm_segment_t old_fs = get_fs();
534         int ret;
535         off_t of;
536 
537         if (offset && get_user(of, offset))
538                 return -EFAULT;
539 
540         set_fs(KERNEL_DS);
541         ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
542         set_fs(old_fs);
543 
544         if (offset && put_user(of, offset))
545                 return -EFAULT;
546 
547         return ret;
548 }
549 
550 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
551 {
552 	mm_segment_t old_fs = get_fs();
553 	int ret;
554 	loff_t lof;
555 
556 	if (offset && get_user(lof, offset))
557 		return -EFAULT;
558 
559 	set_fs(KERNEL_DS);
560 	ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count);
561 	set_fs(old_fs);
562 
563 	if (offset && put_user(lof, offset))
564 		return -EFAULT;
565 
566 	return ret;
567 }
568 
569 
570 struct timex32 {
571 	unsigned int modes;	/* mode selector */
572 	int offset;		/* time offset (usec) */
573 	int freq;		/* frequency offset (scaled ppm) */
574 	int maxerror;		/* maximum error (usec) */
575 	int esterror;		/* estimated error (usec) */
576 	int status;		/* clock command/status */
577 	int constant;		/* pll time constant */
578 	int precision;		/* clock precision (usec) (read only) */
579 	int tolerance;		/* clock frequency tolerance (ppm)
580 				 * (read only)
581 				 */
582 	struct compat_timeval time;	/* (read only) */
583 	int tick;		/* (modified) usecs between clock ticks */
584 
585 	int ppsfreq;           /* pps frequency (scaled ppm) (ro) */
586 	int jitter;            /* pps jitter (us) (ro) */
587 	int shift;              /* interval duration (s) (shift) (ro) */
588 	int stabil;            /* pps stability (scaled ppm) (ro) */
589 	int jitcnt;            /* jitter limit exceeded (ro) */
590 	int calcnt;            /* calibration intervals (ro) */
591 	int errcnt;            /* calibration errors (ro) */
592 	int stbcnt;            /* stability limit exceeded (ro) */
593 
594 	int  :32; int  :32; int  :32; int  :32;
595 	int  :32; int  :32; int  :32; int  :32;
596 	int  :32; int  :32; int  :32; int  :32;
597 };
598 
599 asmlinkage long sys32_adjtimex(struct timex32 __user *txc_p32)
600 {
601 	struct timex txc;
602 	struct timex32 t32;
603 	int ret;
604 	extern int do_adjtimex(struct timex *txc);
605 
606 	if(copy_from_user(&t32, txc_p32, sizeof(struct timex32)))
607 		return -EFAULT;
608 #undef CP
609 #define CP(x) txc.x = t32.x
610 	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
611 	CP(status); CP(constant); CP(precision); CP(tolerance);
612 	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
613 	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
614 	CP(stbcnt);
615 	ret = do_adjtimex(&txc);
616 #undef CP
617 #define CP(x) t32.x = txc.x
618 	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
619 	CP(status); CP(constant); CP(precision); CP(tolerance);
620 	CP(time.tv_sec); CP(time.tv_usec); CP(tick); CP(ppsfreq); CP(jitter);
621 	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
622 	CP(stbcnt);
623 	return copy_to_user(txc_p32, &t32, sizeof(struct timex32)) ? -EFAULT : ret;
624 }
625 
626 
627 struct sysinfo32 {
628 	s32 uptime;
629 	u32 loads[3];
630 	u32 totalram;
631 	u32 freeram;
632 	u32 sharedram;
633 	u32 bufferram;
634 	u32 totalswap;
635 	u32 freeswap;
636 	unsigned short procs;
637 	u32 totalhigh;
638 	u32 freehigh;
639 	u32 mem_unit;
640 	char _f[12];
641 };
642 
643 /* We used to call sys_sysinfo and translate the result.  But sys_sysinfo
644  * undoes the good work done elsewhere, and rather than undoing the
645  * damage, I decided to just duplicate the code from sys_sysinfo here.
646  */
647 
648 asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
649 {
650 	struct sysinfo val;
651 	int err;
652 	unsigned long seq;
653 
654 	/* We don't need a memset here because we copy the
655 	 * struct to userspace once element at a time.
656 	 */
657 
658 	do {
659 		seq = read_seqbegin(&xtime_lock);
660 		val.uptime = jiffies / HZ;
661 
662 		val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
663 		val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
664 		val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
665 
666 		val.procs = nr_threads;
667 	} while (read_seqretry(&xtime_lock, seq));
668 
669 
670 	si_meminfo(&val);
671 	si_swapinfo(&val);
672 
673 	err = put_user (val.uptime, &info->uptime);
674 	err |= __put_user (val.loads[0], &info->loads[0]);
675 	err |= __put_user (val.loads[1], &info->loads[1]);
676 	err |= __put_user (val.loads[2], &info->loads[2]);
677 	err |= __put_user (val.totalram, &info->totalram);
678 	err |= __put_user (val.freeram, &info->freeram);
679 	err |= __put_user (val.sharedram, &info->sharedram);
680 	err |= __put_user (val.bufferram, &info->bufferram);
681 	err |= __put_user (val.totalswap, &info->totalswap);
682 	err |= __put_user (val.freeswap, &info->freeswap);
683 	err |= __put_user (val.procs, &info->procs);
684 	err |= __put_user (val.totalhigh, &info->totalhigh);
685 	err |= __put_user (val.freehigh, &info->freehigh);
686 	err |= __put_user (val.mem_unit, &info->mem_unit);
687 	return err ? -EFAULT : 0;
688 }
689 
690 
691 /* lseek() needs a wrapper because 'offset' can be negative, but the top
692  * half of the argument has been zeroed by syscall.S.
693  */
694 
695 asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin)
696 {
697 	return sys_lseek(fd, offset, origin);
698 }
699 
700 asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg)
701 {
702         union semun u;
703 
704         if (cmd == SETVAL) {
705                 /* Ugh.  arg is a union of int,ptr,ptr,ptr, so is 8 bytes.
706                  * The int should be in the first 4, but our argument
707                  * frobbing has left it in the last 4.
708                  */
709                 u.val = *((int *)&arg + 1);
710                 return sys_semctl (semid, semnum, cmd, u);
711 	}
712 	return sys_semctl (semid, semnum, cmd, arg);
713 }
714 
715 long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
716 			  size_t len)
717 {
718 	return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
719 				  buf, len);
720 }
721