linux/arch/sparc/kernel/sys_sparc32.c
<<
>>
Prefs
   1/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
   2 *
   3 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   4 * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
   5 *
   6 * These routines maintain argument size conversion between 32bit and 64bit
   7 * environment.
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/sched.h>
  12#include <linux/capability.h>
  13#include <linux/fs.h> 
  14#include <linux/mm.h> 
  15#include <linux/file.h> 
  16#include <linux/signal.h>
  17#include <linux/resource.h>
  18#include <linux/times.h>
  19#include <linux/smp.h>
  20#include <linux/sem.h>
  21#include <linux/msg.h>
  22#include <linux/shm.h>
  23#include <linux/uio.h>
  24#include <linux/nfs_fs.h>
  25#include <linux/quota.h>
  26#include <linux/poll.h>
  27#include <linux/personality.h>
  28#include <linux/stat.h>
  29#include <linux/filter.h>
  30#include <linux/highmem.h>
  31#include <linux/highuid.h>
  32#include <linux/mman.h>
  33#include <linux/ipv6.h>
  34#include <linux/in.h>
  35#include <linux/icmpv6.h>
  36#include <linux/syscalls.h>
  37#include <linux/sysctl.h>
  38#include <linux/binfmts.h>
  39#include <linux/dnotify.h>
  40#include <linux/security.h>
  41#include <linux/compat.h>
  42#include <linux/vfs.h>
  43#include <linux/ptrace.h>
  44#include <linux/slab.h>
  45
  46#include <asm/types.h>
  47#include <asm/uaccess.h>
  48#include <asm/fpumacro.h>
  49#include <asm/mmu_context.h>
  50#include <asm/compat_signal.h>
  51
  52#ifdef CONFIG_SYSVIPC                                                        
  53asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
  54{
  55        int version;
  56
  57        version = call >> 16; /* hack for backward compatibility */
  58        call &= 0xffff;
  59
  60        switch (call) {
  61        case SEMTIMEDOP:
  62                if (fifth)
  63                        /* sign extend semid */
  64                        return compat_sys_semtimedop((int)first,
  65                                                     compat_ptr(ptr), second,
  66                                                     compat_ptr(fifth));
  67                /* else fall through for normal semop() */
  68        case SEMOP:
  69                /* struct sembuf is the same on 32 and 64bit :)) */
  70                /* sign extend semid */
  71                return sys_semtimedop((int)first, compat_ptr(ptr), second,
  72                                      NULL);
  73        case SEMGET:
  74                /* sign extend key, nsems */
  75                return sys_semget((int)first, (int)second, third);
  76        case SEMCTL:
  77                /* sign extend semid, semnum */
  78                return compat_sys_semctl((int)first, (int)second, third,
  79                                         compat_ptr(ptr));
  80
  81        case MSGSND:
  82                /* sign extend msqid */
  83                return compat_sys_msgsnd((int)first, (int)second, third,
  84                                         compat_ptr(ptr));
  85        case MSGRCV:
  86                /* sign extend msqid, msgtyp */
  87                return compat_sys_msgrcv((int)first, second, (int)fifth,
  88                                         third, version, compat_ptr(ptr));
  89        case MSGGET:
  90                /* sign extend key */
  91                return sys_msgget((int)first, second);
  92        case MSGCTL:
  93                /* sign extend msqid */
  94                return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
  95
  96        case SHMAT:
  97                /* sign extend shmid */
  98                return compat_sys_shmat((int)first, second, third, version,
  99                                        compat_ptr(ptr));
 100        case SHMDT:
 101                return sys_shmdt(compat_ptr(ptr));
 102        case SHMGET:
 103                /* sign extend key_t */
 104                return sys_shmget((int)first, second, third);
 105        case SHMCTL:
 106                /* sign extend shmid */
 107                return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
 108
 109        default:
 110                return -ENOSYS;
 111        }
 112
 113        return -ENOSYS;
 114}
 115#endif
 116
 117asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
 118{
 119        if ((int)high < 0)
 120                return -EINVAL;
 121        else
 122                return sys_truncate(path, (high << 32) | low);
 123}
 124
 125asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
 126{
 127        if ((int)high < 0)
 128                return -EINVAL;
 129        else
 130                return sys_ftruncate(fd, (high << 32) | low);
 131}
 132
 133static int cp_compat_stat64(struct kstat *stat,
 134                            struct compat_stat64 __user *statbuf)
 135{
 136        int err;
 137
 138        err  = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev);
 139        err |= put_user(stat->ino, &statbuf->st_ino);
 140        err |= put_user(stat->mode, &statbuf->st_mode);
 141        err |= put_user(stat->nlink, &statbuf->st_nlink);
 142        err |= put_user(stat->uid, &statbuf->st_uid);
 143        err |= put_user(stat->gid, &statbuf->st_gid);
 144        err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
 145        err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
 146        err |= put_user(stat->size, &statbuf->st_size);
 147        err |= put_user(stat->blksize, &statbuf->st_blksize);
 148        err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]);
 149        err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]);
 150        err |= put_user(stat->blocks, &statbuf->st_blocks);
 151        err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
 152        err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
 153        err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
 154        err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
 155        err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
 156        err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
 157        err |= put_user(0, &statbuf->__unused4);
 158        err |= put_user(0, &statbuf->__unused5);
 159
 160        return err;
 161}
 162
 163asmlinkage long compat_sys_stat64(const char __user * filename,
 164                struct compat_stat64 __user *statbuf)
 165{
 166        struct kstat stat;
 167        int error = vfs_stat(filename, &stat);
 168
 169        if (!error)
 170                error = cp_compat_stat64(&stat, statbuf);
 171        return error;
 172}
 173
 174asmlinkage long compat_sys_lstat64(const char __user * filename,
 175                struct compat_stat64 __user *statbuf)
 176{
 177        struct kstat stat;
 178        int error = vfs_lstat(filename, &stat);
 179
 180        if (!error)
 181                error = cp_compat_stat64(&stat, statbuf);
 182        return error;
 183}
 184
 185asmlinkage long compat_sys_fstat64(unsigned int fd,
 186                struct compat_stat64 __user * statbuf)
 187{
 188        struct kstat stat;
 189        int error = vfs_fstat(fd, &stat);
 190
 191        if (!error)
 192                error = cp_compat_stat64(&stat, statbuf);
 193        return error;
 194}
 195
 196asmlinkage long compat_sys_fstatat64(unsigned int dfd,
 197                const char __user *filename,
 198                struct compat_stat64 __user * statbuf, int flag)
 199{
 200        struct kstat stat;
 201        int error;
 202
 203        error = vfs_fstatat(dfd, filename, &stat, flag);
 204        if (error)
 205                return error;
 206        return cp_compat_stat64(&stat, statbuf);
 207}
 208
 209asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
 210{
 211        return sys_sysfs(option, arg1, arg2);
 212}
 213
 214asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
 215{
 216        struct timespec t;
 217        int ret;
 218        mm_segment_t old_fs = get_fs ();
 219        
 220        set_fs (KERNEL_DS);
 221        ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
 222        set_fs (old_fs);
 223        if (put_compat_timespec(&t, interval))
 224                return -EFAULT;
 225        return ret;
 226}
 227
 228asmlinkage long compat_sys_rt_sigprocmask(int how,
 229                                          compat_sigset_t __user *set,
 230                                          compat_sigset_t __user *oset,
 231                                          compat_size_t sigsetsize)
 232{
 233        sigset_t s;
 234        compat_sigset_t s32;
 235        int ret;
 236        mm_segment_t old_fs = get_fs();
 237        
 238        if (set) {
 239                if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
 240                        return -EFAULT;
 241                switch (_NSIG_WORDS) {
 242                case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 243                case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 244                case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
 245                case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
 246                }
 247        }
 248        set_fs (KERNEL_DS);
 249        ret = sys_rt_sigprocmask(how,
 250                                 set ? (sigset_t __user *) &s : NULL,
 251                                 oset ? (sigset_t __user *) &s : NULL,
 252                                 sigsetsize);
 253        set_fs (old_fs);
 254        if (ret) return ret;
 255        if (oset) {
 256                switch (_NSIG_WORDS) {
 257                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 258                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 259                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 260                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 261                }
 262                if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
 263                        return -EFAULT;
 264        }
 265        return 0;
 266}
 267
 268asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
 269                                    compat_size_t sigsetsize)
 270{
 271        sigset_t s;
 272        compat_sigset_t s32;
 273        int ret;
 274        mm_segment_t old_fs = get_fs();
 275                
 276        set_fs (KERNEL_DS);
 277        ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
 278        set_fs (old_fs);
 279        if (!ret) {
 280                switch (_NSIG_WORDS) {
 281                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 282                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 283                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 284                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 285                }
 286                if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
 287                        return -EFAULT;
 288        }
 289        return ret;
 290}
 291
 292asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
 293                                           struct compat_siginfo __user *uinfo)
 294{
 295        siginfo_t info;
 296        int ret;
 297        mm_segment_t old_fs = get_fs();
 298        
 299        if (copy_siginfo_from_user32(&info, uinfo))
 300                return -EFAULT;
 301
 302        set_fs (KERNEL_DS);
 303        ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
 304        set_fs (old_fs);
 305        return ret;
 306}
 307
 308asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act,
 309                                     struct old_sigaction32 __user *oact)
 310{
 311        struct k_sigaction new_ka, old_ka;
 312        int ret;
 313
 314        WARN_ON_ONCE(sig >= 0);
 315        sig = -sig;
 316
 317        if (act) {
 318                compat_old_sigset_t mask;
 319                u32 u_handler, u_restorer;
 320                
 321                ret = get_user(u_handler, &act->sa_handler);
 322                new_ka.sa.sa_handler =  compat_ptr(u_handler);
 323                ret |= __get_user(u_restorer, &act->sa_restorer);
 324                new_ka.sa.sa_restorer = compat_ptr(u_restorer);
 325                ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 326                ret |= __get_user(mask, &act->sa_mask);
 327                if (ret)
 328                        return ret;
 329                new_ka.ka_restorer = NULL;
 330                siginitset(&new_ka.sa.sa_mask, mask);
 331        }
 332
 333        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 334
 335        if (!ret && oact) {
 336                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
 337                ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
 338                ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 339                ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 340        }
 341
 342        return ret;
 343}
 344
 345asmlinkage long compat_sys_rt_sigaction(int sig,
 346                                        struct sigaction32 __user *act,
 347                                        struct sigaction32 __user *oact,
 348                                        void __user *restorer,
 349                                        compat_size_t sigsetsize)
 350{
 351        struct k_sigaction new_ka, old_ka;
 352        int ret;
 353        compat_sigset_t set32;
 354
 355        /* XXX: Don't preclude handling different sized sigset_t's.  */
 356        if (sigsetsize != sizeof(compat_sigset_t))
 357                return -EINVAL;
 358
 359        if (act) {
 360                u32 u_handler, u_restorer;
 361
 362                new_ka.ka_restorer = restorer;
 363                ret = get_user(u_handler, &act->sa_handler);
 364                new_ka.sa.sa_handler =  compat_ptr(u_handler);
 365                ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
 366                switch (_NSIG_WORDS) {
 367                case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
 368                case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
 369                case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
 370                case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
 371                }
 372                ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 373                ret |= __get_user(u_restorer, &act->sa_restorer);
 374                new_ka.sa.sa_restorer = compat_ptr(u_restorer);
 375                if (ret)
 376                        return -EFAULT;
 377        }
 378
 379        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 380
 381        if (!ret && oact) {
 382                switch (_NSIG_WORDS) {
 383                case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
 384                case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
 385                case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
 386                case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
 387                }
 388                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
 389                ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
 390                ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 391                ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
 392                if (ret)
 393                        ret = -EFAULT;
 394        }
 395
 396        return ret;
 397}
 398
 399/*
 400 * sparc32_execve() executes a new program after the asm stub has set
 401 * things up for us.  This should basically do what I want it to.
 402 */
 403asmlinkage long sparc32_execve(struct pt_regs *regs)
 404{
 405        int error, base = 0;
 406        char *filename;
 407
 408        /* User register window flush is done by entry.S */
 409
 410        /* Check for indirect call. */
 411        if ((u32)regs->u_regs[UREG_G1] == 0)
 412                base = 1;
 413
 414        filename = getname(compat_ptr(regs->u_regs[base + UREG_I0]));
 415        error = PTR_ERR(filename);
 416        if (IS_ERR(filename))
 417                goto out;
 418
 419        error = compat_do_execve(filename,
 420                                 compat_ptr(regs->u_regs[base + UREG_I1]),
 421                                 compat_ptr(regs->u_regs[base + UREG_I2]), regs);
 422
 423        putname(filename);
 424
 425        if (!error) {
 426                fprs_write(0);
 427                current_thread_info()->xfsr[0] = 0;
 428                current_thread_info()->fpsaved[0] = 0;
 429                regs->tstate &= ~TSTATE_PEF;
 430        }
 431out:
 432        return error;
 433}
 434
 435#ifdef CONFIG_MODULES
 436
 437asmlinkage long sys32_init_module(void __user *umod, u32 len,
 438                                  const char __user *uargs)
 439{
 440        return sys_init_module(umod, len, uargs);
 441}
 442
 443asmlinkage long sys32_delete_module(const char __user *name_user,
 444                                    unsigned int flags)
 445{
 446        return sys_delete_module(name_user, flags);
 447}
 448
 449#else /* CONFIG_MODULES */
 450
 451asmlinkage long sys32_init_module(const char __user *name_user,
 452                                  struct module __user *mod_user)
 453{
 454        return -ENOSYS;
 455}
 456
 457asmlinkage long sys32_delete_module(const char __user *name_user)
 458{
 459        return -ENOSYS;
 460}
 461
 462#endif  /* CONFIG_MODULES */
 463
 464asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
 465                                        char __user *ubuf,
 466                                        compat_size_t count,
 467                                        unsigned long poshi,
 468                                        unsigned long poslo)
 469{
 470        return sys_pread64(fd, ubuf, count, (poshi << 32) | poslo);
 471}
 472
 473asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd,
 474                                         char __user *ubuf,
 475                                         compat_size_t count,
 476                                         unsigned long poshi,
 477                                         unsigned long poslo)
 478{
 479        return sys_pwrite64(fd, ubuf, count, (poshi << 32) | poslo);
 480}
 481
 482asmlinkage long compat_sys_readahead(int fd,
 483                                     unsigned long offhi,
 484                                     unsigned long offlo,
 485                                     compat_size_t count)
 486{
 487        return sys_readahead(fd, (offhi << 32) | offlo, count);
 488}
 489
 490long compat_sys_fadvise64(int fd,
 491                          unsigned long offhi,
 492                          unsigned long offlo,
 493                          compat_size_t len, int advice)
 494{
 495        return sys_fadvise64_64(fd, (offhi << 32) | offlo, len, advice);
 496}
 497
 498long compat_sys_fadvise64_64(int fd,
 499                             unsigned long offhi, unsigned long offlo,
 500                             unsigned long lenhi, unsigned long lenlo,
 501                             int advice)
 502{
 503        return sys_fadvise64_64(fd,
 504                                (offhi << 32) | offlo,
 505                                (lenhi << 32) | lenlo,
 506                                advice);
 507}
 508
 509asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
 510                                    compat_off_t __user *offset,
 511                                    compat_size_t count)
 512{
 513        mm_segment_t old_fs = get_fs();
 514        int ret;
 515        off_t of;
 516        
 517        if (offset && get_user(of, offset))
 518                return -EFAULT;
 519                
 520        set_fs(KERNEL_DS);
 521        ret = sys_sendfile(out_fd, in_fd,
 522                           offset ? (off_t __user *) &of : NULL,
 523                           count);
 524        set_fs(old_fs);
 525        
 526        if (offset && put_user(of, offset))
 527                return -EFAULT;
 528                
 529        return ret;
 530}
 531
 532asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd,
 533                                      compat_loff_t __user *offset,
 534                                      compat_size_t count)
 535{
 536        mm_segment_t old_fs = get_fs();
 537        int ret;
 538        loff_t lof;
 539        
 540        if (offset && get_user(lof, offset))
 541                return -EFAULT;
 542                
 543        set_fs(KERNEL_DS);
 544        ret = sys_sendfile64(out_fd, in_fd,
 545                             offset ? (loff_t __user *) &lof : NULL,
 546                             count);
 547        set_fs(old_fs);
 548        
 549        if (offset && put_user(lof, offset))
 550                return -EFAULT;
 551                
 552        return ret;
 553}
 554
 555/* This is just a version for 32-bit applications which does
 556 * not force O_LARGEFILE on.
 557 */
 558
 559asmlinkage long sparc32_open(const char __user *filename,
 560                             int flags, int mode)
 561{
 562        return do_sys_open(AT_FDCWD, filename, flags, mode);
 563}
 564
 565long sys32_lookup_dcookie(unsigned long cookie_high,
 566                          unsigned long cookie_low,
 567                          char __user *buf, size_t len)
 568{
 569        return sys_lookup_dcookie((cookie_high << 32) | cookie_low,
 570                                  buf, len);
 571}
 572
 573long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags)
 574{
 575        return sys_sync_file_range(fd,
 576                                   (off_high << 32) | off_low,
 577                                   (nb_high << 32) | nb_low,
 578                                   flags);
 579}
 580
 581asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
 582                                     u32 lenhi, u32 lenlo)
 583{
 584        return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
 585                             ((loff_t)lenhi << 32) | lenlo);
 586}
 587