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