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