linux/arch/x86/ia32/sys_ia32.c History
<<
>>
Prefs
   1/*
   2 * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
   3 *             sys_sparc32
   4 *
   5 * Copyright (C) 2000           VA Linux Co
   6 * Copyright (C) 2000           Don Dugger <n0ano@valinux.com>
   7 * Copyright (C) 1999           Arun Sharma <arun.sharma@intel.com>
   8 * Copyright (C) 1997,1998      Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   9 * Copyright (C) 1997           David S. Miller (davem@caip.rutgers.edu)
  10 * Copyright (C) 2000           Hewlett-Packard Co.
  11 * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
  12 * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port)
  13 *
  14 * These routines maintain argument size conversion between 32bit and 64bit
  15 * environment. In 2.5 most of this should be moved to a generic directory.
  16 *
  17 * This file assumes that there is a hole at the end of user address space.
  18 *
  19 * Some of the functions are LE specific currently. These are
  20 * hopefully all marked.  This should be fixed.
  21 */
  22
  23#include <linux/kernel.h>
  24#include <linux/sched.h>
  25#include <linux/fs.h>
  26#include <linux/file.h>
  27#include <linux/signal.h>
  28#include <linux/syscalls.h>
  29#include <linux/times.h>
  30#include <linux/utsname.h>
  31#include <linux/smp_lock.h>
  32#include <linux/mm.h>
  33#include <linux/uio.h>
  34#include <linux/poll.h>
  35#include <linux/personality.h>
  36#include <linux/stat.h>
  37#include <linux/rwsem.h>
  38#include <linux/compat.h>
  39#include <linux/vfs.h>
  40#include <linux/ptrace.h>
  41#include <linux/highuid.h>
  42#include <linux/sysctl.h>
  43#include <asm/mman.h>
  44#include <asm/types.h>
  45#include <asm/uaccess.h>
  46#include <asm/atomic.h>
  47#include <asm/vgtod.h>
  48#include <asm/sys_ia32.h>
  49
  50#define AA(__x)         ((unsigned long)(__x))
  51
  52
  53asmlinkage long sys32_truncate64(char __user *filename,
  54                                 unsigned long offset_low,
  55                                 unsigned long offset_high)
  56{
  57       return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
  58}
  59
  60asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low,
  61                                  unsigned long offset_high)
  62{
  63       return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
  64}
  65
  66/*
  67 * Another set for IA32/LFS -- x86_64 struct stat is different due to
  68 * support for 64bit inode numbers.
  69 */
  70static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
  71{
  72        typeof(ubuf->st_uid) uid = 0;
  73        typeof(ubuf->st_gid) gid = 0;
  74        SET_UID(uid, stat->uid);
  75        SET_GID(gid, stat->gid);
  76        if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
  77            __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
  78            __put_user(stat->ino, &ubuf->__st_ino) ||
  79            __put_user(stat->ino, &ubuf->st_ino) ||
  80            __put_user(stat->mode, &ubuf->st_mode) ||
  81            __put_user(stat->nlink, &ubuf->st_nlink) ||
  82            __put_user(uid, &ubuf->st_uid) ||
  83            __put_user(gid, &ubuf->st_gid) ||
  84            __put_user(huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
  85            __put_user(stat->size, &ubuf->st_size) ||
  86            __put_user(stat->atime.tv_sec, &ubuf->st_atime) ||
  87            __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec) ||
  88            __put_user(stat->mtime.tv_sec, &ubuf->st_mtime) ||
  89            __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
  90            __put_user(stat->ctime.tv_sec, &ubuf->st_ctime) ||
  91            __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
  92            __put_user(stat->blksize, &ubuf->st_blksize) ||
  93            __put_user(stat->blocks, &ubuf->st_blocks))
  94                return -EFAULT;
  95        return 0;
  96}
  97
  98asmlinkage long sys32_stat64(char __user *filename,
  99                             struct stat64 __user *statbuf)
 100{
 101        struct kstat stat;
 102        int ret = vfs_stat(filename, &stat);
 103
 104        if (!ret)
 105                ret = cp_stat64(statbuf, &stat);
 106        return ret;
 107}
 108
 109asmlinkage long sys32_lstat64(char __user *filename,
 110                              struct stat64 __user *statbuf)
 111{
 112        struct kstat stat;
 113        int ret = vfs_lstat(filename, &stat);
 114        if (!ret)
 115                ret = cp_stat64(statbuf, &stat);
 116        return ret;
 117}
 118
 119asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
 120{
 121        struct kstat stat;
 122        int ret = vfs_fstat(fd, &stat);
 123        if (!ret)
 124                ret = cp_stat64(statbuf, &stat);
 125        return ret;
 126}
 127
 128asmlinkage long sys32_fstatat(unsigned int dfd, char __user *filename,
 129                              struct stat64 __user *statbuf, int flag)
 130{
 131        struct kstat stat;
 132        int error;
 133
 134        error = vfs_fstatat(dfd, filename, &stat, flag);
 135        if (error)
 136                return error;
 137        return cp_stat64(statbuf, &stat);
 138}
 139
 140/*
 141 * Linux/i386 didn't use to be able to handle more than
 142 * 4 system call parameters, so these system calls used a memory
 143 * block for parameter passing..
 144 */
 145
 146struct mmap_arg_struct {
 147        unsigned int addr;
 148        unsigned int len;
 149        unsigned int prot;
 150        unsigned int flags;
 151        unsigned int fd;
 152        unsigned int offset;
 153};
 154
 155asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg)
 156{
 157        struct mmap_arg_struct a;
 158        struct file *file = NULL;
 159        unsigned long retval;
 160        struct mm_struct *mm ;
 161
 162        if (copy_from_user(&a, arg, sizeof(a)))
 163                return -EFAULT;
 164
 165        if (a.offset & ~PAGE_MASK)
 166                return -EINVAL;
 167
 168        if (!(a.flags & MAP_ANONYMOUS)) {
 169                file = fget(a.fd);
 170                if (!file)
 171                        return -EBADF;
 172        }
 173
 174        mm = current->mm;
 175        down_write(&mm->mmap_sem);
 176        retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags,
 177                               a.offset>>PAGE_SHIFT);
 178        if (file)
 179                fput(file);
 180
 181        up_write(&mm->mmap_sem);
 182
 183        return retval;
 184}
 185
 186asmlinkage long sys32_mprotect(unsigned long start, size_t len,
 187                               unsigned long prot)
 188{
 189        return sys_mprotect(start, len, prot);
 190}
 191
 192asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
 193                                   struct sigaction32 __user *oact,
 194                                   unsigned int sigsetsize)
 195{
 196        struct k_sigaction new_ka, old_ka;
 197        int ret;
 198        compat_sigset_t set32;
 199
 200        /* XXX: Don't preclude handling different sized sigset_t's.  */
 201        if (sigsetsize != sizeof(compat_sigset_t))
 202                return -EINVAL;
 203
 204        if (act) {
 205                compat_uptr_t handler, restorer;
 206
 207                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 208                    __get_user(handler, &act->sa_handler) ||
 209                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 210                    __get_user(restorer, &act->sa_restorer) ||
 211                    __copy_from_user(&set32, &act->sa_mask,
 212                                     sizeof(compat_sigset_t)))
 213                        return -EFAULT;
 214                new_ka.sa.sa_handler = compat_ptr(handler);
 215                new_ka.sa.sa_restorer = compat_ptr(restorer);
 216
 217                /*
 218                 * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
 219                 * than _NSIG_WORDS << 1
 220                 */
 221                switch (_NSIG_WORDS) {
 222                case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
 223                                | (((long)set32.sig[7]) << 32);
 224                case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
 225                                | (((long)set32.sig[5]) << 32);
 226                case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
 227                                | (((long)set32.sig[3]) << 32);
 228                case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
 229                                | (((long)set32.sig[1]) << 32);
 230                }
 231        }
 232
 233        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 234
 235        if (!ret && oact) {
 236                /*
 237                 * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
 238                 * than _NSIG_WORDS << 1
 239                 */
 240                switch (_NSIG_WORDS) {
 241                case 4:
 242                        set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
 243                        set32.sig[6] = old_ka.sa.sa_mask.sig[3];
 244                case 3:
 245                        set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
 246                        set32.sig[4] = old_ka.sa.sa_mask.sig[2];
 247                case 2:
 248                        set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
 249                        set32.sig[2] = old_ka.sa.sa_mask.sig[1];
 250                case 1:
 251                        set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
 252                        set32.sig[0] = old_ka.sa.sa_mask.sig[0];
 253                }
 254                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 255                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
 256                               &oact->sa_handler) ||
 257                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
 258                               &oact->sa_restorer) ||
 259                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 260                    __copy_to_user(&oact->sa_mask, &set32,
 261                                   sizeof(compat_sigset_t)))
 262                        return -EFAULT;
 263        }
 264
 265        return ret;
 266}
 267
 268asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
 269                                struct old_sigaction32 __user *oact)
 270{
 271        struct k_sigaction new_ka, old_ka;
 272        int ret;
 273
 274        if (act) {
 275                compat_old_sigset_t mask;
 276                compat_uptr_t handler, restorer;
 277
 278                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 279                    __get_user(handler, &act->sa_handler) ||
 280                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 281                    __get_user(restorer, &act->sa_restorer) ||
 282                    __get_user(mask, &act->sa_mask))
 283                        return -EFAULT;
 284
 285                new_ka.sa.sa_handler = compat_ptr(handler);
 286                new_ka.sa.sa_restorer = compat_ptr(restorer);
 287
 288                siginitset(&new_ka.sa.sa_mask, mask);
 289        }
 290
 291        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 292
 293        if (!ret && oact) {
 294                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 295                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
 296                               &oact->sa_handler) ||
 297                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
 298                               &oact->sa_restorer) ||
 299                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 300                    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
 301                        return -EFAULT;
 302        }
 303
 304        return ret;
 305}
 306
 307asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
 308                                     compat_sigset_t __user *oset,
 309                                     unsigned int sigsetsize)
 310{
 311        sigset_t s;
 312        compat_sigset_t s32;
 313        int ret;
 314        mm_segment_t old_fs = get_fs();
 315
 316        if (set) {
 317                if (copy_from_user(&s32, set, sizeof(compat_sigset_t)))
 318                        return -EFAULT;
 319                switch (_NSIG_WORDS) {
 320                case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 321                case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 322                case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
 323                case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
 324                }
 325        }
 326        set_fs(KERNEL_DS);
 327        ret = sys_rt_sigprocmask(how,
 328                                 set ? (sigset_t __user *)&s : NULL,
 329                                 oset ? (sigset_t __user *)&s : NULL,
 330                                 sigsetsize);
 331        set_fs(old_fs);
 332        if (ret)
 333                return ret;
 334        if (oset) {
 335                switch (_NSIG_WORDS) {
 336                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 337                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 338                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 339                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 340                }
 341                if (copy_to_user(oset, &s32, sizeof(compat_sigset_t)))
 342                        return -EFAULT;
 343        }
 344        return 0;
 345}
 346
 347asmlinkage long sys32_alarm(unsigned int seconds)
 348{
 349        return alarm_setitimer(seconds);
 350}
 351
 352struct sel_arg_struct {
 353        unsigned int n;
 354        unsigned int inp;
 355        unsigned int outp;
 356        unsigned int exp;
 357        unsigned int tvp;
 358};
 359
 360asmlinkage long sys32_old_select(struct sel_arg_struct __user *arg)
 361{
 362        struct sel_arg_struct a;
 363
 364        if (copy_from_user(&a, arg, sizeof(a)))
 365                return -EFAULT;
 366        return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
 367                                 compat_ptr(a.exp), compat_ptr(a.tvp));
 368}
 369
 370asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
 371                              int options)
 372{
 373        return compat_sys_wait4(pid, stat_addr, options, NULL);
 374}
 375
 376/* 32-bit timeval and related flotsam.  */
 377
 378asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2)
 379{
 380        return sys_sysfs(option, arg1, arg2);
 381}
 382
 383asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
 384                                    struct compat_timespec __user *interval)
 385{
 386        struct timespec t;
 387        int ret;
 388        mm_segment_t old_fs = get_fs();
 389
 390        set_fs(KERNEL_DS);
 391        ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
 392        set_fs(old_fs);
 393        if (put_compat_timespec(&t, interval))
 394                return -EFAULT;
 395        return ret;
 396}
 397
 398asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
 399                                    compat_size_t sigsetsize)
 400{
 401        sigset_t s;
 402        compat_sigset_t s32;
 403        int ret;
 404        mm_segment_t old_fs = get_fs();
 405
 406        set_fs(KERNEL_DS);
 407        ret = sys_rt_sigpending((sigset_t __user *)&s, sigsetsize);
 408        set_fs(old_fs);
 409        if (!ret) {
 410                switch (_NSIG_WORDS) {
 411                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 412                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 413                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 414                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 415                }
 416                if (copy_to_user(set, &s32, sizeof(compat_sigset_t)))
 417                        return -EFAULT;
 418        }
 419        return ret;
 420}
 421
 422asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig,
 423                                      compat_siginfo_t __user *uinfo)
 424{
 425        siginfo_t info;
 426        int ret;
 427        mm_segment_t old_fs = get_fs();
 428
 429        if (copy_siginfo_from_user32(&info, uinfo))
 430                return -EFAULT;
 431        set_fs(KERNEL_DS);
 432        ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
 433        set_fs(old_fs);
 434        return ret;
 435}
 436
 437#ifdef CONFIG_SYSCTL_SYSCALL
 438struct sysctl_ia32 {
 439        unsigned int    name;
 440        int             nlen;
 441        unsigned int    oldval;
 442        unsigned int    oldlenp;
 443        unsigned int    newval;
 444        unsigned int    newlen;
 445        unsigned int    __unused[4];
 446};
 447
 448
 449asmlinkage long sys32_sysctl(struct sysctl_ia32 __user *args32)
 450{
 451        struct sysctl_ia32 a32;
 452        mm_segment_t old_fs = get_fs();
 453        void __user *oldvalp, *newvalp;
 454        size_t oldlen;
 455        int __user *namep;
 456        long ret;
 457
 458        if (copy_from_user(&a32, args32, sizeof(a32)))
 459                return -EFAULT;
 460
 461        /*
 462         * We need to pre-validate these because we have to disable
 463         * address checking before calling do_sysctl() because of
 464         * OLDLEN but we can't run the risk of the user specifying bad
 465         * addresses here.  Well, since we're dealing with 32 bit
 466         * addresses, we KNOW that access_ok() will always succeed, so
 467         * this is an expensive NOP, but so what...
 468         */
 469        namep = compat_ptr(a32.name);
 470        oldvalp = compat_ptr(a32.oldval);
 471        newvalp =  compat_ptr(a32.newval);
 472
 473        if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
 474            || !access_ok(VERIFY_WRITE, namep, 0)
 475            || !access_ok(VERIFY_WRITE, oldvalp, 0)
 476            || !access_ok(VERIFY_WRITE, newvalp, 0))
 477                return -EFAULT;
 478
 479        set_fs(KERNEL_DS);
 480        lock_kernel();
 481        ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *)&oldlen,
 482                        newvalp, (size_t) a32.newlen);
 483        unlock_kernel();
 484        set_fs(old_fs);
 485
 486        if (oldvalp && put_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
 487                return -EFAULT;
 488
 489        return ret;
 490}
 491#endif
 492
 493/* warning: next two assume little endian */
 494asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
 495                            u32 poslo, u32 poshi)
 496{
 497        return sys_pread64(fd, ubuf, count,
 498                         ((loff_t)AA(poshi) << 32) | AA(poslo));
 499}
 500
 501asmlinkage long sys32_pwrite(unsigned int fd, char __user *ubuf, u32 count,
 502                             u32 poslo, u32 poshi)
 503{
 504        return sys_pwrite64(fd, ubuf, count,
 505                          ((loff_t)AA(poshi) << 32) | AA(poslo));
 506}
 507
 508
 509asmlinkage long sys32_personality(unsigned long personality)
 510{
 511        int ret;
 512
 513        if (personality(current->personality) == PER_LINUX32 &&
 514                personality == PER_LINUX)
 515                personality = PER_LINUX32;
 516        ret = sys_personality(personality);
 517        if (ret == PER_LINUX32)
 518                ret = PER_LINUX;
 519        return ret;
 520}
 521
 522asmlinkage long sys32_sendfile(int out_fd, int in_fd,
 523                               compat_off_t __user *offset, s32 count)
 524{
 525        mm_segment_t old_fs = get_fs();
 526        int ret;
 527        off_t of;
 528
 529        if (offset && get_user(of, offset))
 530                return -EFAULT;
 531
 532        set_fs(KERNEL_DS);
 533        ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
 534                           count);
 535        set_fs(old_fs);
 536
 537        if (offset && put_user(of, offset))
 538                return -EFAULT;
 539        return ret;
 540}
 541
 542asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 543                            unsigned long prot, unsigned long flags,
 544                            unsigned long fd, unsigned long pgoff)
 545{
 546        struct mm_struct *mm = current->mm;
 547        unsigned long error;
 548        struct file *file = NULL;
 549
 550        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 551        if (!(flags & MAP_ANONYMOUS)) {
 552                file = fget(fd);
 553                if (!file)
 554                        return -EBADF;
 555        }
 556
 557        down_write(&mm->mmap_sem);
 558        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 559        up_write(&mm->mmap_sem);
 560
 561        if (file)
 562                fput(file);
 563        return error;
 564}
 565
 566asmlinkage long sys32_olduname(struct oldold_utsname __user *name)
 567{
 568        char *arch = "x86_64";
 569        int err;
 570
 571        if (!name)
 572                return -EFAULT;
 573        if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
 574                return -EFAULT;
 575
 576        down_read(&uts_sem);
 577
 578        err = __copy_to_user(&name->sysname, &utsname()->sysname,
 579                             __OLD_UTS_LEN);
 580        err |= __put_user(0, name->sysname+__OLD_UTS_LEN);
 581        err |= __copy_to_user(&name->nodename, &utsname()->nodename,
 582                              __OLD_UTS_LEN);
 583        err |= __put_user(0, name->nodename+__OLD_UTS_LEN);
 584        err |= __copy_to_user(&name->release, &utsname()->release,
 585                              __OLD_UTS_LEN);
 586        err |= __put_user(0, name->release+__OLD_UTS_LEN);
 587        err |= __copy_to_user(&name->version, &utsname()->version,
 588                              __OLD_UTS_LEN);
 589        err |= __put_user(0, name->version+__OLD_UTS_LEN);
 590
 591        if (personality(current->personality) == PER_LINUX32)
 592                arch = "i686";
 593
 594        err |= __copy_to_user(&name->machine, arch, strlen(arch) + 1);
 595
 596        up_read(&uts_sem);
 597
 598        err = err ? -EFAULT : 0;
 599
 600        return err;
 601}
 602
 603long sys32_uname(struct old_utsname __user *name)
 604{
 605        int err;
 606
 607        if (!name)
 608                return -EFAULT;
 609        down_read(&uts_sem);
 610        err = copy_to_user(name, utsname(), sizeof(*name));
 611        up_read(&uts_sem);
 612        if (personality(current->personality) == PER_LINUX32)
 613                err |= copy_to_user(&name->machine, "i686", 5);
 614
 615        return err ? -EFAULT : 0;
 616}
 617
 618asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
 619                             compat_uptr_t __user *envp, struct pt_regs *regs)
 620{
 621        long error;
 622        char *filename;
 623
 624        filename = getname(name);
 625        error = PTR_ERR(filename);
 626        if (IS_ERR(filename))
 627                return error;
 628        error = compat_do_execve(filename, argv, envp, regs);
 629        putname(filename);
 630        return error;
 631}
 632
 633asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
 634                            struct pt_regs *regs)
 635{
 636        void __user *parent_tid = (void __user *)regs->dx;
 637        void __user *child_tid = (void __user *)regs->di;
 638
 639        if (!newsp)
 640                newsp = regs->sp;
 641        return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
 642}
 643
 644/*
 645 * Some system calls that need sign extended arguments. This could be
 646 * done by a generic wrapper.
 647 */
 648long sys32_lseek(unsigned int fd, int offset, unsigned int whence)
 649{
 650        return sys_lseek(fd, offset, whence);
 651}
 652
 653long sys32_kill(int pid, int sig)
 654{
 655        return sys_kill(pid, sig);
 656}
 657
 658long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
 659                        __u32 len_low, __u32 len_high, int advice)
 660{
 661        return sys_fadvise64_64(fd,
 662                               (((u64)offset_high)<<32) | offset_low,
 663                               (((u64)len_high)<<32) | len_low,
 664                                advice);
 665}
 666
 667long sys32_vm86_warning(void)
 668{
 669        struct task_struct *me = current;
 670        static char lastcomm[sizeof(me->comm)];
 671
 672        if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
 673                compat_printk(KERN_INFO
 674                              "%s: vm86 mode not supported on 64 bit kernel\n",
 675                              me->comm);
 676                strncpy(lastcomm, me->comm, sizeof(lastcomm));
 677        }
 678        return -ENOSYS;
 679}
 680
 681long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
 682                          char __user *buf, size_t len)
 683{
 684        return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
 685}
 686
 687asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
 688                                   size_t count)
 689{
 690        return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
 691}
 692
 693asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi,
 694                                      unsigned n_low, unsigned n_hi,  int flags)
 695{
 696        return sys_sync_file_range(fd,
 697                                   ((u64)off_hi << 32) | off_low,
 698                                   ((u64)n_hi << 32) | n_low, flags);
 699}
 700
 701asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
 702                                size_t len, int advice)
 703{
 704        return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
 705                                len, advice);
 706}
 707
 708asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
 709                                unsigned offset_hi, unsigned len_lo,
 710                                unsigned len_hi)
 711{
 712        return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
 713                             ((u64)len_hi << 32) | len_lo);
 714}
 715
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.