linux/arch/x86/ia32/sys_ia32.c
<<
>>
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_pipe(int __user *fd)
 193{
 194        int retval;
 195        int fds[2];
 196
 197        retval = do_pipe_flags(fds, 0);
 198        if (retval)
 199                goto out;
 200        if (copy_to_user(fd, fds, sizeof(fds)))
 201                retval = -EFAULT;
 202out:
 203        return retval;
 204}
 205
 206asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
 207                                   struct sigaction32 __user *oact,
 208                                   unsigned int sigsetsize)
 209{
 210        struct k_sigaction new_ka, old_ka;
 211        int ret;
 212        compat_sigset_t set32;
 213
 214        /* XXX: Don't preclude handling different sized sigset_t's.  */
 215        if (sigsetsize != sizeof(compat_sigset_t))
 216                return -EINVAL;
 217
 218        if (act) {
 219                compat_uptr_t handler, restorer;
 220
 221                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 222                    __get_user(handler, &act->sa_handler) ||
 223                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 224                    __get_user(restorer, &act->sa_restorer) ||
 225                    __copy_from_user(&set32, &act->sa_mask,
 226                                     sizeof(compat_sigset_t)))
 227                        return -EFAULT;
 228                new_ka.sa.sa_handler = compat_ptr(handler);
 229                new_ka.sa.sa_restorer = compat_ptr(restorer);
 230
 231                /*
 232                 * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
 233                 * than _NSIG_WORDS << 1
 234                 */
 235                switch (_NSIG_WORDS) {
 236                case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
 237                                | (((long)set32.sig[7]) << 32);
 238                case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
 239                                | (((long)set32.sig[5]) << 32);
 240                case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
 241                                | (((long)set32.sig[3]) << 32);
 242                case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
 243                                | (((long)set32.sig[1]) << 32);
 244                }
 245        }
 246
 247        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 248
 249        if (!ret && oact) {
 250                /*
 251                 * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
 252                 * than _NSIG_WORDS << 1
 253                 */
 254                switch (_NSIG_WORDS) {
 255                case 4:
 256                        set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
 257                        set32.sig[6] = old_ka.sa.sa_mask.sig[3];
 258                case 3:
 259                        set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
 260                        set32.sig[4] = old_ka.sa.sa_mask.sig[2];
 261                case 2:
 262                        set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
 263                        set32.sig[2] = old_ka.sa.sa_mask.sig[1];
 264                case 1:
 265                        set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
 266                        set32.sig[0] = old_ka.sa.sa_mask.sig[0];
 267                }
 268                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 269                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
 270                               &oact->sa_handler) ||
 271                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
 272                               &oact->sa_restorer) ||
 273                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 274                    __copy_to_user(&oact->sa_mask, &set32,
 275                                   sizeof(compat_sigset_t)))
 276                        return -EFAULT;
 277        }
 278
 279        return ret;
 280}
 281
 282asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
 283                                struct old_sigaction32 __user *oact)
 284{
 285        struct k_sigaction new_ka, old_ka;
 286        int ret;
 287
 288        if (act) {
 289                compat_old_sigset_t mask;
 290                compat_uptr_t handler, restorer;
 291
 292                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 293                    __get_user(handler, &act->sa_handler) ||
 294                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 295                    __get_user(restorer, &act->sa_restorer) ||
 296                    __get_user(mask, &act->sa_mask))
 297                        return -EFAULT;
 298
 299                new_ka.sa.sa_handler = compat_ptr(handler);
 300                new_ka.sa.sa_restorer = compat_ptr(restorer);
 301
 302                siginitset(&new_ka.sa.sa_mask, mask);
 303        }
 304
 305        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 306
 307        if (!ret && oact) {
 308                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 309                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
 310                               &oact->sa_handler) ||
 311                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
 312                               &oact->sa_restorer) ||
 313                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 314                    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
 315                        return -EFAULT;
 316        }
 317
 318        return ret;
 319}
 320
 321asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
 322                                     compat_sigset_t __user *oset,
 323                                     unsigned int sigsetsize)
 324{
 325        sigset_t s;
 326        compat_sigset_t s32;
 327        int ret;
 328        mm_segment_t old_fs = get_fs();
 329
 330        if (set) {
 331                if (copy_from_user(&s32, set, sizeof(compat_sigset_t)))
 332                        return -EFAULT;
 333                switch (_NSIG_WORDS) {
 334                case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 335                case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 336                case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
 337                case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
 338                }
 339        }
 340        set_fs(KERNEL_DS);
 341        ret = sys_rt_sigprocmask(how,
 342                                 set ? (sigset_t __user *)&s : NULL,
 343                                 oset ? (sigset_t __user *)&s : NULL,
 344                                 sigsetsize);
 345        set_fs(old_fs);
 346        if (ret)
 347                return ret;
 348        if (oset) {
 349                switch (_NSIG_WORDS) {
 350                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 351                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 352                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 353                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 354                }
 355                if (copy_to_user(oset, &s32, sizeof(compat_sigset_t)))
 356                        return -EFAULT;
 357        }
 358        return 0;
 359}
 360
 361asmlinkage long sys32_alarm(unsigned int seconds)
 362{
 363        return alarm_setitimer(seconds);
 364}
 365
 366struct sel_arg_struct {
 367        unsigned int n;
 368        unsigned int inp;
 369        unsigned int outp;
 370        unsigned int exp;
 371        unsigned int tvp;
 372};
 373
 374asmlinkage long sys32_old_select(struct sel_arg_struct __user *arg)
 375{
 376        struct sel_arg_struct a;
 377
 378        if (copy_from_user(&a, arg, sizeof(a)))
 379                return -EFAULT;
 380        return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
 381                                 compat_ptr(a.exp), compat_ptr(a.tvp));
 382}
 383
 384asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
 385                              int options)
 386{
 387        return compat_sys_wait4(pid, stat_addr, options, NULL);
 388}
 389
 390/* 32-bit timeval and related flotsam.  */
 391
 392asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2)
 393{
 394        return sys_sysfs(option, arg1, arg2);
 395}
 396
 397asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
 398                                    struct compat_timespec __user *interval)
 399{
 400        struct timespec t;
 401        int ret;
 402        mm_segment_t old_fs = get_fs();
 403
 404        set_fs(KERNEL_DS);
 405        ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
 406        set_fs(old_fs);
 407        if (put_compat_timespec(&t, interval))
 408                return -EFAULT;
 409        return ret;
 410}
 411
 412asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
 413                                    compat_size_t sigsetsize)
 414{
 415        sigset_t s;
 416        compat_sigset_t s32;
 417        int ret;
 418        mm_segment_t old_fs = get_fs();
 419
 420        set_fs(KERNEL_DS);
 421        ret = sys_rt_sigpending((sigset_t __user *)&s, sigsetsize);
 422        set_fs(old_fs);
 423        if (!ret) {
 424                switch (_NSIG_WORDS) {
 425                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 426                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 427                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 428                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 429                }
 430                if (copy_to_user(set, &s32, sizeof(compat_sigset_t)))
 431                        return -EFAULT;
 432        }
 433        return ret;
 434}
 435
 436asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig,
 437                                      compat_siginfo_t __user *uinfo)
 438{
 439        siginfo_t info;
 440        int ret;
 441        mm_segment_t old_fs = get_fs();
 442
 443        if (copy_siginfo_from_user32(&info, uinfo))
 444                return -EFAULT;
 445        set_fs(KERNEL_DS);
 446        ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
 447        set_fs(old_fs);
 448        return ret;
 449}
 450
 451#ifdef CONFIG_SYSCTL_SYSCALL
 452struct sysctl_ia32 {
 453        unsigned int    name;
 454        int             nlen;
 455        unsigned int    oldval;
 456        unsigned int    oldlenp;
 457        unsigned int    newval;
 458        unsigned int    newlen;
 459        unsigned int    __unused[4];
 460};
 461
 462
 463asmlinkage long sys32_sysctl(struct sysctl_ia32 __user *args32)
 464{
 465        struct sysctl_ia32 a32;
 466        mm_segment_t old_fs = get_fs();
 467        void __user *oldvalp, *newvalp;
 468        size_t oldlen;
 469        int __user *namep;
 470        long ret;
 471
 472        if (copy_from_user(&a32, args32, sizeof(a32)))
 473                return -EFAULT;
 474
 475        /*
 476         * We need to pre-validate these because we have to disable
 477         * address checking before calling do_sysctl() because of
 478         * OLDLEN but we can't run the risk of the user specifying bad
 479         * addresses here.  Well, since we're dealing with 32 bit
 480         * addresses, we KNOW that access_ok() will always succeed, so
 481         * this is an expensive NOP, but so what...
 482         */
 483        namep = compat_ptr(a32.name);
 484        oldvalp = compat_ptr(a32.oldval);
 485        newvalp =  compat_ptr(a32.newval);
 486
 487        if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
 488            || !access_ok(VERIFY_WRITE, namep, 0)
 489            || !access_ok(VERIFY_WRITE, oldvalp, 0)
 490            || !access_ok(VERIFY_WRITE, newvalp, 0))
 491                return -EFAULT;
 492
 493        set_fs(KERNEL_DS);
 494        lock_kernel();
 495        ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *)&oldlen,
 496                        newvalp, (size_t) a32.newlen);
 497        unlock_kernel();
 498        set_fs(old_fs);
 499
 500        if (oldvalp && put_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
 501                return -EFAULT;
 502
 503        return ret;
 504}
 505#endif
 506
 507/* warning: next two assume little endian */
 508asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
 509                            u32 poslo, u32 poshi)
 510{
 511        return sys_pread64(fd, ubuf, count,
 512                         ((loff_t)AA(poshi) << 32) | AA(poslo));
 513}
 514
 515asmlinkage long sys32_pwrite(unsigned int fd, char __user *ubuf, u32 count,
 516                             u32 poslo, u32 poshi)
 517{
 518        return sys_pwrite64(fd, ubuf, count,
 519                          ((loff_t)AA(poshi) << 32) | AA(poslo));
 520}
 521
 522
 523asmlinkage long sys32_personality(unsigned long personality)
 524{
 525        int ret;
 526
 527        if (personality(current->personality) == PER_LINUX32 &&
 528                personality == PER_LINUX)
 529                personality = PER_LINUX32;
 530        ret = sys_personality(personality);
 531        if (ret == PER_LINUX32)
 532                ret = PER_LINUX;
 533        return ret;
 534}
 535
 536asmlinkage long sys32_sendfile(int out_fd, int in_fd,
 537                               compat_off_t __user *offset, s32 count)
 538{
 539        mm_segment_t old_fs = get_fs();
 540        int ret;
 541        off_t of;
 542
 543        if (offset && get_user(of, offset))
 544                return -EFAULT;
 545
 546        set_fs(KERNEL_DS);
 547        ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
 548                           count);
 549        set_fs(old_fs);
 550
 551        if (offset && put_user(of, offset))
 552                return -EFAULT;
 553        return ret;
 554}
 555
 556asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 557                            unsigned long prot, unsigned long flags,
 558                            unsigned long fd, unsigned long pgoff)
 559{
 560        struct mm_struct *mm = current->mm;
 561        unsigned long error;
 562        struct file *file = NULL;
 563
 564        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 565        if (!(flags & MAP_ANONYMOUS)) {
 566                file = fget(fd);
 567                if (!file)
 568                        return -EBADF;
 569        }
 570
 571        down_write(&mm->mmap_sem);
 572        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 573        up_write(&mm->mmap_sem);
 574
 575        if (file)
 576                fput(file);
 577        return error;
 578}
 579
 580asmlinkage long sys32_olduname(struct oldold_utsname __user *name)
 581{
 582        char *arch = "x86_64";
 583        int err;
 584
 585        if (!name)
 586                return -EFAULT;
 587        if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
 588                return -EFAULT;
 589
 590        down_read(&uts_sem);
 591
 592        err = __copy_to_user(&name->sysname, &utsname()->sysname,
 593                             __OLD_UTS_LEN);
 594        err |= __put_user(0, name->sysname+__OLD_UTS_LEN);
 595        err |= __copy_to_user(&name->nodename, &utsname()->nodename,
 596                              __OLD_UTS_LEN);
 597        err |= __put_user(0, name->nodename+__OLD_UTS_LEN);
 598        err |= __copy_to_user(&name->release, &utsname()->release,
 599                              __OLD_UTS_LEN);
 600        err |= __put_user(0, name->release+__OLD_UTS_LEN);
 601        err |= __copy_to_user(&name->version, &utsname()->version,
 602                              __OLD_UTS_LEN);
 603        err |= __put_user(0, name->version+__OLD_UTS_LEN);
 604
 605        if (personality(current->personality) == PER_LINUX32)
 606                arch = "i686";
 607
 608        err |= __copy_to_user(&name->machine, arch, strlen(arch) + 1);
 609
 610        up_read(&uts_sem);
 611
 612        err = err ? -EFAULT : 0;
 613
 614        return err;
 615}
 616
 617long sys32_uname(struct old_utsname __user *name)
 618{
 619        int err;
 620
 621        if (!name)
 622                return -EFAULT;
 623        down_read(&uts_sem);
 624        err = copy_to_user(name, utsname(), sizeof(*name));
 625        up_read(&uts_sem);
 626        if (personality(current->personality) == PER_LINUX32)
 627                err |= copy_to_user(&name->machine, "i686", 5);
 628
 629        return err ? -EFAULT : 0;
 630}
 631
 632asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
 633                             compat_uptr_t __user *envp, struct pt_regs *regs)
 634{
 635        long error;
 636        char *filename;
 637
 638        filename = getname(name);
 639        error = PTR_ERR(filename);
 640        if (IS_ERR(filename))
 641                return error;
 642        error = compat_do_execve(filename, argv, envp, regs);
 643        putname(filename);
 644        return error;
 645}
 646
 647asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
 648                            struct pt_regs *regs)
 649{
 650        void __user *parent_tid = (void __user *)regs->dx;
 651        void __user *child_tid = (void __user *)regs->di;
 652
 653        if (!newsp)
 654                newsp = regs->sp;
 655        return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
 656}
 657
 658/*
 659 * Some system calls that need sign extended arguments. This could be
 660 * done by a generic wrapper.
 661 */
 662long sys32_lseek(unsigned int fd, int offset, unsigned int whence)
 663{
 664        return sys_lseek(fd, offset, whence);
 665}
 666
 667long sys32_kill(int pid, int sig)
 668{
 669        return sys_kill(pid, sig);
 670}
 671
 672long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
 673                        __u32 len_low, __u32 len_high, int advice)
 674{
 675        return sys_fadvise64_64(fd,
 676                               (((u64)offset_high)<<32) | offset_low,
 677                               (((u64)len_high)<<32) | len_low,
 678                                advice);
 679}
 680
 681long sys32_vm86_warning(void)
 682{
 683        struct task_struct *me = current;
 684        static char lastcomm[sizeof(me->comm)];
 685
 686        if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
 687                compat_printk(KERN_INFO
 688                              "%s: vm86 mode not supported on 64 bit kernel\n",
 689                              me->comm);
 690                strncpy(lastcomm, me->comm, sizeof(lastcomm));
 691        }
 692        return -ENOSYS;
 693}
 694
 695long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
 696                          char __user *buf, size_t len)
 697{
 698        return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
 699}
 700
 701asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
 702                                   size_t count)
 703{
 704        return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
 705}
 706
 707asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi,
 708                                      unsigned n_low, unsigned n_hi,  int flags)
 709{
 710        return sys_sync_file_range(fd,
 711                                   ((u64)off_hi << 32) | off_low,
 712                                   ((u64)n_hi << 32) | n_low, flags);
 713}
 714
 715asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
 716                                size_t len, int advice)
 717{
 718        return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
 719                                len, advice);
 720}
 721
 722asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
 723                                unsigned offset_hi, unsigned len_lo,
 724                                unsigned len_hi)
 725{
 726        return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
 727                             ((u64)len_hi << 32) | len_lo);
 728}
 729
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.