linux/arch/alpha/kernel/osf_sys.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/alpha/kernel/osf_sys.c
   3 *
   4 *  Copyright (C) 1995  Linus Torvalds
   5 */
   6
   7/*
   8 * This file handles some of the stranger OSF/1 system call interfaces.
   9 * Some of the system calls expect a non-C calling standard, others have
  10 * special parameter blocks..
  11 */
  12
  13#include <linux/errno.h>
  14#include <linux/sched.h>
  15#include <linux/kernel.h>
  16#include <linux/mm.h>
  17#include <linux/smp.h>
  18#include <linux/smp_lock.h>
  19#include <linux/stddef.h>
  20#include <linux/syscalls.h>
  21#include <linux/unistd.h>
  22#include <linux/ptrace.h>
  23#include <linux/slab.h>
  24#include <linux/user.h>
  25#include <linux/utsname.h>
  26#include <linux/time.h>
  27#include <linux/timex.h>
  28#include <linux/major.h>
  29#include <linux/stat.h>
  30#include <linux/mman.h>
  31#include <linux/shm.h>
  32#include <linux/poll.h>
  33#include <linux/file.h>
  34#include <linux/types.h>
  35#include <linux/ipc.h>
  36#include <linux/namei.h>
  37#include <linux/uio.h>
  38#include <linux/vfs.h>
  39#include <linux/rcupdate.h>
  40
  41#include <asm/fpu.h>
  42#include <asm/io.h>
  43#include <asm/uaccess.h>
  44#include <asm/system.h>
  45#include <asm/sysinfo.h>
  46#include <asm/hwrpb.h>
  47#include <asm/processor.h>
  48
  49extern int do_pipe(int *);
  50
  51/*
  52 * Brk needs to return an error.  Still support Linux's brk(0) query idiom,
  53 * which OSF programs just shouldn't be doing.  We're still not quite
  54 * identical to OSF as we don't return 0 on success, but doing otherwise
  55 * would require changes to libc.  Hopefully this is good enough.
  56 */
  57asmlinkage unsigned long
  58osf_brk(unsigned long brk)
  59{
  60        unsigned long retval = sys_brk(brk);
  61        if (brk && brk != retval)
  62                retval = -ENOMEM;
  63        return retval;
  64}
  65 
  66/*
  67 * This is pure guess-work..
  68 */
  69asmlinkage int
  70osf_set_program_attributes(unsigned long text_start, unsigned long text_len,
  71                           unsigned long bss_start, unsigned long bss_len)
  72{
  73        struct mm_struct *mm;
  74
  75        lock_kernel();
  76        mm = current->mm;
  77        mm->end_code = bss_start + bss_len;
  78        mm->start_brk = bss_start + bss_len;
  79        mm->brk = bss_start + bss_len;
  80#if 0
  81        printk("set_program_attributes(%lx %lx %lx %lx)\n",
  82                text_start, text_len, bss_start, bss_len);
  83#endif
  84        unlock_kernel();
  85        return 0;
  86}
  87
  88/*
  89 * OSF/1 directory handling functions...
  90 *
  91 * The "getdents()" interface is much more sane: the "basep" stuff is
  92 * braindamage (it can't really handle filesystems where the directory
  93 * offset differences aren't the same as "d_reclen").
  94 */
  95#define NAME_OFFSET     offsetof (struct osf_dirent, d_name)
  96
  97struct osf_dirent {
  98        unsigned int d_ino;
  99        unsigned short d_reclen;
 100        unsigned short d_namlen;
 101        char d_name[1];
 102};
 103
 104struct osf_dirent_callback {
 105        struct osf_dirent __user *dirent;
 106        long __user *basep;
 107        unsigned int count;
 108        int error;
 109};
 110
 111static int
 112osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
 113            u64 ino, unsigned int d_type)
 114{
 115        struct osf_dirent __user *dirent;
 116        struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
 117        unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));
 118        unsigned int d_ino;
 119
 120        buf->error = -EINVAL;   /* only used if we fail */
 121        if (reclen > buf->count)
 122                return -EINVAL;
 123        d_ino = ino;
 124        if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 125                buf->error = -EOVERFLOW;
 126                return -EOVERFLOW;
 127        }
 128        if (buf->basep) {
 129                if (put_user(offset, buf->basep))
 130                        goto Efault;
 131                buf->basep = NULL;
 132        }
 133        dirent = buf->dirent;
 134        if (put_user(d_ino, &dirent->d_ino) ||
 135            put_user(namlen, &dirent->d_namlen) ||
 136            put_user(reclen, &dirent->d_reclen) ||
 137            copy_to_user(dirent->d_name, name, namlen) ||
 138            put_user(0, dirent->d_name + namlen))
 139                goto Efault;
 140        dirent = (void __user *)dirent + reclen;
 141        buf->dirent = dirent;
 142        buf->count -= reclen;
 143        return 0;
 144Efault:
 145        buf->error = -EFAULT;
 146        return -EFAULT;
 147}
 148
 149asmlinkage int
 150osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent,
 151                  unsigned int count, long __user *basep)
 152{
 153        int error;
 154        struct file *file;
 155        struct osf_dirent_callback buf;
 156
 157        error = -EBADF;
 158        file = fget(fd);
 159        if (!file)
 160                goto out;
 161
 162        buf.dirent = dirent;
 163        buf.basep = basep;
 164        buf.count = count;
 165        buf.error = 0;
 166
 167        error = vfs_readdir(file, osf_filldir, &buf);
 168        if (error >= 0)
 169                error = buf.error;
 170        if (count != buf.count)
 171                error = count - buf.count;
 172
 173        fput(file);
 174 out:
 175        return error;
 176}
 177
 178#undef NAME_OFFSET
 179
 180asmlinkage unsigned long
 181osf_mmap(unsigned long addr, unsigned long len, unsigned long prot,
 182         unsigned long flags, unsigned long fd, unsigned long off)
 183{
 184        struct file *file = NULL;
 185        unsigned long ret = -EBADF;
 186
 187#if 0
 188        if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
 189                printk("%s: unimplemented OSF mmap flags %04lx\n", 
 190                        current->comm, flags);
 191#endif
 192        if (!(flags & MAP_ANONYMOUS)) {
 193                file = fget(fd);
 194                if (!file)
 195                        goto out;
 196        }
 197        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 198        down_write(&current->mm->mmap_sem);
 199        ret = do_mmap(file, addr, len, prot, flags, off);
 200        up_write(&current->mm->mmap_sem);
 201        if (file)
 202                fput(file);
 203 out:
 204        return ret;
 205}
 206
 207
 208/*
 209 * The OSF/1 statfs structure is much larger, but this should
 210 * match the beginning, at least.
 211 */
 212struct osf_statfs {
 213        short f_type;
 214        short f_flags;
 215        int f_fsize;
 216        int f_bsize;
 217        int f_blocks;
 218        int f_bfree;
 219        int f_bavail;
 220        int f_files;
 221        int f_ffree;
 222        __kernel_fsid_t f_fsid;
 223};
 224
 225static int
 226linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_stat,
 227                    unsigned long bufsiz)
 228{
 229        struct osf_statfs tmp_stat;
 230
 231        tmp_stat.f_type = linux_stat->f_type;
 232        tmp_stat.f_flags = 0;   /* mount flags */
 233        tmp_stat.f_fsize = linux_stat->f_frsize;
 234        tmp_stat.f_bsize = linux_stat->f_bsize;
 235        tmp_stat.f_blocks = linux_stat->f_blocks;
 236        tmp_stat.f_bfree = linux_stat->f_bfree;
 237        tmp_stat.f_bavail = linux_stat->f_bavail;
 238        tmp_stat.f_files = linux_stat->f_files;
 239        tmp_stat.f_ffree = linux_stat->f_ffree;
 240        tmp_stat.f_fsid = linux_stat->f_fsid;
 241        if (bufsiz > sizeof(tmp_stat))
 242                bufsiz = sizeof(tmp_stat);
 243        return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
 244}
 245
 246static int
 247do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
 248              unsigned long bufsiz)
 249{
 250        struct kstatfs linux_stat;
 251        int error = vfs_statfs(dentry, &linux_stat);
 252        if (!error)
 253                error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
 254        return error;   
 255}
 256
 257asmlinkage int
 258osf_statfs(char __user *pathname, struct osf_statfs __user *buffer, unsigned long bufsiz)
 259{
 260        struct path path;
 261        int retval;
 262
 263        retval = user_path(pathname, &path);
 264        if (!retval) {
 265                retval = do_osf_statfs(path.dentry, buffer, bufsiz);
 266                path_put(&path);
 267        }
 268        return retval;
 269}
 270
 271asmlinkage int
 272osf_fstatfs(unsigned long fd, struct osf_statfs __user *buffer, unsigned long bufsiz)
 273{
 274        struct file *file;
 275        int retval;
 276
 277        retval = -EBADF;
 278        file = fget(fd);
 279        if (file) {
 280                retval = do_osf_statfs(file->f_path.dentry, buffer, bufsiz);
 281                fput(file);
 282        }
 283        return retval;
 284}
 285
 286/*
 287 * Uhh.. OSF/1 mount parameters aren't exactly obvious..
 288 *
 289 * Although to be frank, neither are the native Linux/i386 ones..
 290 */
 291struct ufs_args {
 292        char __user *devname;
 293        int flags;
 294        uid_t exroot;
 295};
 296
 297struct cdfs_args {
 298        char __user *devname;
 299        int flags;
 300        uid_t exroot;
 301
 302        /* This has lots more here, which Linux handles with the option block
 303           but I'm too lazy to do the translation into ASCII.  */
 304};
 305
 306struct procfs_args {
 307        char __user *devname;
 308        int flags;
 309        uid_t exroot;
 310};
 311
 312/*
 313 * We can't actually handle ufs yet, so we translate UFS mounts to
 314 * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
 315 * layout is so braindead it's a major headache doing it.
 316 *
 317 * Just how long ago was it written? OTOH our UFS driver may be still
 318 * unhappy with OSF UFS. [CHECKME]
 319 */
 320static int
 321osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
 322{
 323        int retval;
 324        struct cdfs_args tmp;
 325        char *devname;
 326
 327        retval = -EFAULT;
 328        if (copy_from_user(&tmp, args, sizeof(tmp)))
 329                goto out;
 330        devname = getname(tmp.devname);
 331        retval = PTR_ERR(devname);
 332        if (IS_ERR(devname))
 333                goto out;
 334        retval = do_mount(devname, dirname, "ext2", flags, NULL);
 335        putname(devname);
 336 out:
 337        return retval;
 338}
 339
 340static int
 341osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
 342{
 343        int retval;
 344        struct cdfs_args tmp;
 345        char *devname;
 346
 347        retval = -EFAULT;
 348        if (copy_from_user(&tmp, args, sizeof(tmp)))
 349                goto out;
 350        devname = getname(tmp.devname);
 351        retval = PTR_ERR(devname);
 352        if (IS_ERR(devname))
 353                goto out;
 354        retval = do_mount(devname, dirname, "iso9660", flags, NULL);
 355        putname(devname);
 356 out:
 357        return retval;
 358}
 359
 360static int
 361osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags)
 362{
 363        struct procfs_args tmp;
 364
 365        if (copy_from_user(&tmp, args, sizeof(tmp)))
 366                return -EFAULT;
 367
 368        return do_mount("", dirname, "proc", flags, NULL);
 369}
 370
 371asmlinkage int
 372osf_mount(unsigned long typenr, char __user *path, int flag, void __user *data)
 373{
 374        int retval = -EINVAL;
 375        char *name;
 376
 377        lock_kernel();
 378
 379        name = getname(path);
 380        retval = PTR_ERR(name);
 381        if (IS_ERR(name))
 382                goto out;
 383        switch (typenr) {
 384        case 1:
 385                retval = osf_ufs_mount(name, data, flag);
 386                break;
 387        case 6:
 388                retval = osf_cdfs_mount(name, data, flag);
 389                break;
 390        case 9:
 391                retval = osf_procfs_mount(name, data, flag);
 392                break;
 393        default:
 394                printk("osf_mount(%ld, %x)\n", typenr, flag);
 395        }
 396        putname(name);
 397 out:
 398        unlock_kernel();
 399        return retval;
 400}
 401
 402asmlinkage int
 403osf_utsname(char __user *name)
 404{
 405        int error;
 406
 407        down_read(&uts_sem);
 408        error = -EFAULT;
 409        if (copy_to_user(name + 0, utsname()->sysname, 32))
 410                goto out;
 411        if (copy_to_user(name + 32, utsname()->nodename, 32))
 412                goto out;
 413        if (copy_to_user(name + 64, utsname()->release, 32))
 414                goto out;
 415        if (copy_to_user(name + 96, utsname()->version, 32))
 416                goto out;
 417        if (copy_to_user(name + 128, utsname()->machine, 32))
 418                goto out;
 419
 420        error = 0;
 421 out:
 422        up_read(&uts_sem);      
 423        return error;
 424}
 425
 426asmlinkage unsigned long
 427sys_getpagesize(void)
 428{
 429        return PAGE_SIZE;
 430}
 431
 432asmlinkage unsigned long
 433sys_getdtablesize(void)
 434{
 435        return sysctl_nr_open;
 436}
 437
 438/*
 439 * For compatibility with OSF/1 only.  Use utsname(2) instead.
 440 */
 441asmlinkage int
 442osf_getdomainname(char __user *name, int namelen)
 443{
 444        unsigned len;
 445        int i;
 446
 447        if (!access_ok(VERIFY_WRITE, name, namelen))
 448                return -EFAULT;
 449
 450        len = namelen;
 451        if (namelen > 32)
 452                len = 32;
 453
 454        down_read(&uts_sem);
 455        for (i = 0; i < len; ++i) {
 456                __put_user(utsname()->domainname[i], name + i);
 457                if (utsname()->domainname[i] == '\0')
 458                        break;
 459        }
 460        up_read(&uts_sem);
 461
 462        return 0;
 463}
 464
 465/*
 466 * The following stuff should move into a header file should it ever
 467 * be labeled "officially supported."  Right now, there is just enough
 468 * support to avoid applications (such as tar) printing error
 469 * messages.  The attributes are not really implemented.
 470 */
 471
 472/*
 473 * Values for Property list entry flag
 474 */
 475#define PLE_PROPAGATE_ON_COPY           0x1     /* cp(1) will copy entry
 476                                                   by default */
 477#define PLE_FLAG_MASK                   0x1     /* Valid flag values */
 478#define PLE_FLAG_ALL                    -1      /* All flag value */
 479
 480struct proplistname_args {
 481        unsigned int pl_mask;
 482        unsigned int pl_numnames;
 483        char **pl_names;
 484};
 485
 486union pl_args {
 487        struct setargs {
 488                char __user *path;
 489                long follow;
 490                long nbytes;
 491                char __user *buf;
 492        } set;
 493        struct fsetargs {
 494                long fd;
 495                long nbytes;
 496                char __user *buf;
 497        } fset;
 498        struct getargs {
 499                char __user *path;
 500                long follow;
 501                struct proplistname_args __user *name_args;
 502                long nbytes;
 503                char __user *buf;
 504                int __user *min_buf_size;
 505        } get;
 506        struct fgetargs {
 507                long fd;
 508                struct proplistname_args __user *name_args;
 509                long nbytes;
 510                char __user *buf;
 511                int __user *min_buf_size;
 512        } fget;
 513        struct delargs {
 514                char __user *path;
 515                long follow;
 516                struct proplistname_args __user *name_args;
 517        } del;
 518        struct fdelargs {
 519                long fd;
 520                struct proplistname_args __user *name_args;
 521        } fdel;
 522};
 523
 524enum pl_code {
 525        PL_SET = 1, PL_FSET = 2,
 526        PL_GET = 3, PL_FGET = 4,
 527        PL_DEL = 5, PL_FDEL = 6
 528};
 529
 530asmlinkage long
 531osf_proplist_syscall(enum pl_code code, union pl_args __user *args)
 532{
 533        long error;
 534        int __user *min_buf_size_ptr;
 535
 536        lock_kernel();
 537        switch (code) {
 538        case PL_SET:
 539                if (get_user(error, &args->set.nbytes))
 540                        error = -EFAULT;
 541                break;
 542        case PL_FSET:
 543                if (get_user(error, &args->fset.nbytes))
 544                        error = -EFAULT;
 545                break;
 546        case PL_GET:
 547                error = get_user(min_buf_size_ptr, &args->get.min_buf_size);
 548                if (error)
 549                        break;
 550                error = put_user(0, min_buf_size_ptr);
 551                break;
 552        case PL_FGET:
 553                error = get_user(min_buf_size_ptr, &args->fget.min_buf_size);
 554                if (error)
 555                        break;
 556                error = put_user(0, min_buf_size_ptr);
 557                break;
 558        case PL_DEL:
 559        case PL_FDEL:
 560                error = 0;
 561                break;
 562        default:
 563                error = -EOPNOTSUPP;
 564                break;
 565        };
 566        unlock_kernel();
 567        return error;
 568}
 569
 570asmlinkage int
 571osf_sigstack(struct sigstack __user *uss, struct sigstack __user *uoss)
 572{
 573        unsigned long usp = rdusp();
 574        unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
 575        unsigned long oss_os = on_sig_stack(usp);
 576        int error;
 577
 578        if (uss) {
 579                void __user *ss_sp;
 580
 581                error = -EFAULT;
 582                if (get_user(ss_sp, &uss->ss_sp))
 583                        goto out;
 584
 585                /* If the current stack was set with sigaltstack, don't
 586                   swap stacks while we are on it.  */
 587                error = -EPERM;
 588                if (current->sas_ss_sp && on_sig_stack(usp))
 589                        goto out;
 590
 591                /* Since we don't know the extent of the stack, and we don't
 592                   track onstack-ness, but rather calculate it, we must 
 593                   presume a size.  Ho hum this interface is lossy.  */
 594                current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
 595                current->sas_ss_size = SIGSTKSZ;
 596        }
 597
 598        if (uoss) {
 599                error = -EFAULT;
 600                if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))
 601                    || __put_user(oss_sp, &uoss->ss_sp)
 602                    || __put_user(oss_os, &uoss->ss_onstack))
 603                        goto out;
 604        }
 605
 606        error = 0;
 607 out:
 608        return error;
 609}
 610
 611asmlinkage long
 612osf_sysinfo(int command, char __user *buf, long count)
 613{
 614        char *sysinfo_table[] = {
 615                utsname()->sysname,
 616                utsname()->nodename,
 617                utsname()->release,
 618                utsname()->version,
 619                utsname()->machine,
 620                "alpha",        /* instruction set architecture */
 621                "dummy",        /* hardware serial number */
 622                "dummy",        /* hardware manufacturer */
 623                "dummy",        /* secure RPC domain */
 624        };
 625        unsigned long offset;
 626        char *res;
 627        long len, err = -EINVAL;
 628
 629        offset = command-1;
 630        if (offset >= ARRAY_SIZE(sysinfo_table)) {
 631                /* Digital UNIX has a few unpublished interfaces here */
 632                printk("sysinfo(%d)", command);
 633                goto out;
 634        }
 635
 636        down_read(&uts_sem);
 637        res = sysinfo_table[offset];
 638        len = strlen(res)+1;
 639        if (len > count)
 640                len = count;
 641        if (copy_to_user(buf, res, len))
 642                err = -EFAULT;
 643        else
 644                err = 0;
 645        up_read(&uts_sem);
 646 out:
 647        return err;
 648}
 649
 650asmlinkage unsigned long
 651osf_getsysinfo(unsigned long op, void __user *buffer, unsigned long nbytes,
 652               int __user *start, void __user *arg)
 653{
 654        unsigned long w;
 655        struct percpu_struct *cpu;
 656
 657        switch (op) {
 658        case GSI_IEEE_FP_CONTROL:
 659                /* Return current software fp control & status bits.  */
 660                /* Note that DU doesn't verify available space here.  */
 661
 662                w = current_thread_info()->ieee_state & IEEE_SW_MASK;
 663                w = swcr_update_status(w, rdfpcr());
 664                if (put_user(w, (unsigned long __user *) buffer))
 665                        return -EFAULT;
 666                return 0;
 667
 668        case GSI_IEEE_STATE_AT_SIGNAL:
 669                /*
 670                 * Not sure anybody will ever use this weird stuff.  These
 671                 * ops can be used (under OSF/1) to set the fpcr that should
 672                 * be used when a signal handler starts executing.
 673                 */
 674                break;
 675
 676        case GSI_UACPROC:
 677                if (nbytes < sizeof(unsigned int))
 678                        return -EINVAL;
 679                w = (current_thread_info()->flags >> UAC_SHIFT) & UAC_BITMASK;
 680                if (put_user(w, (unsigned int __user *)buffer))
 681                        return -EFAULT;
 682                return 1;
 683
 684        case GSI_PROC_TYPE:
 685                if (nbytes < sizeof(unsigned long))
 686                        return -EINVAL;
 687                cpu = (struct percpu_struct*)
 688                  ((char*)hwrpb + hwrpb->processor_offset);
 689                w = cpu->type;
 690                if (put_user(w, (unsigned long  __user*)buffer))
 691                        return -EFAULT;
 692                return 1;
 693
 694        case GSI_GET_HWRPB:
 695                if (nbytes < sizeof(*hwrpb))
 696                        return -EINVAL;
 697                if (copy_to_user(buffer, hwrpb, nbytes) != 0)
 698                        return -EFAULT;
 699                return 1;
 700
 701        default:
 702                break;
 703        }
 704
 705        return -EOPNOTSUPP;
 706}
 707
 708asmlinkage unsigned long
 709osf_setsysinfo(unsigned long op, void __user *buffer, unsigned long nbytes,
 710               int __user *start, void __user *arg)
 711{
 712        switch (op) {
 713        case SSI_IEEE_FP_CONTROL: {
 714                unsigned long swcr, fpcr;
 715                unsigned int *state;
 716
 717                /* 
 718                 * Alpha Architecture Handbook 4.7.7.3:
 719                 * To be fully IEEE compiant, we must track the current IEEE
 720                 * exception state in software, because spurious bits can be
 721                 * set in the trap shadow of a software-complete insn.
 722                 */
 723
 724                if (get_user(swcr, (unsigned long __user *)buffer))
 725                        return -EFAULT;
 726                state = &current_thread_info()->ieee_state;
 727
 728                /* Update softare trap enable bits.  */
 729                *state = (*state & ~IEEE_SW_MASK) | (swcr & IEEE_SW_MASK);
 730
 731                /* Update the real fpcr.  */
 732                fpcr = rdfpcr() & FPCR_DYN_MASK;
 733                fpcr |= ieee_swcr_to_fpcr(swcr);
 734                wrfpcr(fpcr);
 735
 736                return 0;
 737        }
 738
 739        case SSI_IEEE_RAISE_EXCEPTION: {
 740                unsigned long exc, swcr, fpcr, fex;
 741                unsigned int *state;
 742
 743                if (get_user(exc, (unsigned long __user *)buffer))
 744                        return -EFAULT;
 745                state = &current_thread_info()->ieee_state;
 746                exc &= IEEE_STATUS_MASK;
 747
 748                /* Update softare trap enable bits.  */
 749                swcr = (*state & IEEE_SW_MASK) | exc;
 750                *state |= exc;
 751
 752                /* Update the real fpcr.  */
 753                fpcr = rdfpcr();
 754                fpcr |= ieee_swcr_to_fpcr(swcr);
 755                wrfpcr(fpcr);
 756
 757                /* If any exceptions set by this call, and are unmasked,
 758                   send a signal.  Old exceptions are not signaled.  */
 759                fex = (exc >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr;
 760                if (fex) {
 761                        siginfo_t info;
 762                        int si_code = 0;
 763
 764                        if (fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
 765                        if (fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
 766                        if (fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
 767                        if (fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
 768                        if (fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
 769                        if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;
 770
 771                        info.si_signo = SIGFPE;
 772                        info.si_errno = 0;
 773                        info.si_code = si_code;
 774                        info.si_addr = NULL;  /* FIXME */
 775                        send_sig_info(SIGFPE, &info, current);
 776                }
 777                return 0;
 778        }
 779
 780        case SSI_IEEE_STATE_AT_SIGNAL:
 781        case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
 782                /*
 783                 * Not sure anybody will ever use this weird stuff.  These
 784                 * ops can be used (under OSF/1) to set the fpcr that should
 785                 * be used when a signal handler starts executing.
 786                 */
 787                break;
 788
 789        case SSI_NVPAIRS: {
 790                unsigned long v, w, i;
 791                unsigned int old, new;
 792                
 793                for (i = 0; i < nbytes; ++i) {
 794
 795                        if (get_user(v, 2*i + (unsigned int __user *)buffer))
 796                                return -EFAULT;
 797                        if (get_user(w, 2*i + 1 + (unsigned int __user *)buffer))
 798                                return -EFAULT;
 799                        switch (v) {
 800                        case SSIN_UACPROC:
 801                        again:
 802                                old = current_thread_info()->flags;
 803                                new = old & ~(UAC_BITMASK << UAC_SHIFT);
 804                                new = new | (w & UAC_BITMASK) << UAC_SHIFT;
 805                                if (cmpxchg(&current_thread_info()->flags,
 806                                            old, new) != old)
 807                                        goto again;
 808                                break;
 809 
 810                        default:
 811                                return -EOPNOTSUPP;
 812                        }
 813                }
 814                return 0;
 815        }
 816 
 817        default:
 818                break;
 819        }
 820
 821        return -EOPNOTSUPP;
 822}
 823
 824/* Translations due to the fact that OSF's time_t is an int.  Which
 825   affects all sorts of things, like timeval and itimerval.  */
 826
 827extern struct timezone sys_tz;
 828
 829struct timeval32
 830{
 831    int tv_sec, tv_usec;
 832};
 833
 834struct itimerval32
 835{
 836    struct timeval32 it_interval;
 837    struct timeval32 it_value;
 838};
 839
 840static inline long
 841get_tv32(struct timeval *o, struct timeval32 __user *i)
 842{
 843        return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 844                (__get_user(o->tv_sec, &i->tv_sec) |
 845                 __get_user(o->tv_usec, &i->tv_usec)));
 846}
 847
 848static inline long
 849put_tv32(struct timeval32 __user *o, struct timeval *i)
 850{
 851        return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 852                (__put_user(i->tv_sec, &o->tv_sec) |
 853                 __put_user(i->tv_usec, &o->tv_usec)));
 854}
 855
 856static inline long
 857get_it32(struct itimerval *o, struct itimerval32 __user *i)
 858{
 859        return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 860                (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
 861                 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
 862                 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
 863                 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
 864}
 865
 866static inline long
 867put_it32(struct itimerval32 __user *o, struct itimerval *i)
 868{
 869        return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 870                (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
 871                 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
 872                 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
 873                 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
 874}
 875
 876static inline void
 877jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value)
 878{
 879        value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
 880        value->tv_sec = jiffies / HZ;
 881}
 882
 883asmlinkage int
 884osf_gettimeofday(struct timeval32 __user *tv, struct timezone __user *tz)
 885{
 886        if (tv) {
 887                struct timeval ktv;
 888                do_gettimeofday(&ktv);
 889                if (put_tv32(tv, &ktv))
 890                        return -EFAULT;
 891        }
 892        if (tz) {
 893                if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
 894                        return -EFAULT;
 895        }
 896        return 0;
 897}
 898
 899asmlinkage int
 900osf_settimeofday(struct timeval32 __user *tv, struct timezone __user *tz)
 901{
 902        struct timespec kts;
 903        struct timezone ktz;
 904
 905        if (tv) {
 906                if (get_tv32((struct timeval *)&kts, tv))
 907                        return -EFAULT;
 908        }
 909        if (tz) {
 910                if (copy_from_user(&ktz, tz, sizeof(*tz)))
 911                        return -EFAULT;
 912        }
 913
 914        kts.tv_nsec *= 1000;
 915
 916        return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 917}
 918
 919asmlinkage int
 920osf_getitimer(int which, struct itimerval32 __user *it)
 921{
 922        struct itimerval kit;
 923        int error;
 924
 925        error = do_getitimer(which, &kit);
 926        if (!error && put_it32(it, &kit))
 927                error = -EFAULT;
 928
 929        return error;
 930}
 931
 932asmlinkage int
 933osf_setitimer(int which, struct itimerval32 __user *in, struct itimerval32 __user *out)
 934{
 935        struct itimerval kin, kout;
 936        int error;
 937
 938        if (in) {
 939                if (get_it32(&kin, in))
 940                        return -EFAULT;
 941        } else
 942                memset(&kin, 0, sizeof(kin));
 943
 944        error = do_setitimer(which, &kin, out ? &kout : NULL);
 945        if (error || !out)
 946                return error;
 947
 948        if (put_it32(out, &kout))
 949                return -EFAULT;
 950
 951        return 0;
 952
 953}
 954
 955asmlinkage int
 956osf_utimes(char __user *filename, struct timeval32 __user *tvs)
 957{
 958        struct timespec tv[2];
 959
 960        if (tvs) {
 961                struct timeval ktvs[2];
 962                if (get_tv32(&ktvs[0], &tvs[0]) ||
 963                    get_tv32(&ktvs[1], &tvs[1]))
 964                        return -EFAULT;
 965
 966                if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
 967                    ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
 968                        return -EINVAL;
 969
 970                tv[0].tv_sec = ktvs[0].tv_sec;
 971                tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
 972                tv[1].tv_sec = ktvs[1].tv_sec;
 973                tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
 974        }
 975
 976        return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
 977}
 978
 979#define MAX_SELECT_SECONDS \
 980        ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 981
 982asmlinkage int
 983osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
 984           struct timeval32 __user *tvp)
 985{
 986        struct timespec end_time, *to = NULL;
 987        if (tvp) {
 988                time_t sec, usec;
 989
 990                to = &end_time;
 991
 992                if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
 993                    || __get_user(sec, &tvp->tv_sec)
 994                    || __get_user(usec, &tvp->tv_usec)) {
 995                        return -EFAULT;
 996                }
 997
 998                if (sec < 0 || usec < 0)
 999                        return -EINVAL;
1000
1001                if (poll_select_set_timeout(to, sec, usec * NSEC_PER_USEC))
1002                        return -EINVAL;         
1003
1004        }
1005
1006        /* OSF does not copy back the remaining time.  */
1007        return core_sys_select(n, inp, outp, exp, to);
1008}
1009
1010struct rusage32 {
1011        struct timeval32 ru_utime;      /* user time used */
1012        struct timeval32 ru_stime;      /* system time used */
1013        long    ru_maxrss;              /* maximum resident set size */
1014        long    ru_ixrss;               /* integral shared memory size */
1015        long    ru_idrss;               /* integral unshared data size */
1016        long    ru_isrss;               /* integral unshared stack size */
1017        long    ru_minflt;              /* page reclaims */
1018        long    ru_majflt;              /* page faults */
1019        long    ru_nswap;               /* swaps */
1020        long    ru_inblock;             /* block input operations */
1021        long    ru_oublock;             /* block output operations */
1022        long    ru_msgsnd;              /* messages sent */
1023        long    ru_msgrcv;              /* messages received */
1024        long    ru_nsignals;            /* signals received */
1025        long    ru_nvcsw;               /* voluntary context switches */
1026        long    ru_nivcsw;              /* involuntary " */
1027};
1028
1029asmlinkage int
1030osf_getrusage(int who, struct rusage32 __user *ru)
1031{
1032        struct rusage32 r;
1033
1034        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
1035                return -EINVAL;
1036
1037        memset(&r, 0, sizeof(r));
1038        switch (who) {
1039        case RUSAGE_SELF:
1040                jiffies_to_timeval32(current->utime, &r.ru_utime);
1041                jiffies_to_timeval32(current->stime, &r.ru_stime);
1042                r.ru_minflt = current->min_flt;
1043                r.ru_majflt = current->maj_flt;
1044                break;
1045        case RUSAGE_CHILDREN:
1046                jiffies_to_timeval32(current->signal->cutime, &r.ru_utime);
1047                jiffies_to_timeval32(current->signal->cstime, &r.ru_stime);
1048                r.ru_minflt = current->signal->cmin_flt;
1049                r.ru_majflt = current->signal->cmaj_flt;
1050                break;
1051        }
1052
1053        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
1054}
1055
1056asmlinkage long
1057osf_wait4(pid_t pid, int __user *ustatus, int options,
1058          struct rusage32 __user *ur)
1059{
1060        struct rusage r;
1061        long ret, err;
1062        mm_segment_t old_fs;
1063
1064        if (!ur)
1065                return sys_wait4(pid, ustatus, options, NULL);
1066
1067        old_fs = get_fs();
1068                
1069        set_fs (KERNEL_DS);
1070        ret = sys_wait4(pid, ustatus, options, (struct rusage __user *) &r);
1071        set_fs (old_fs);
1072
1073        if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
1074                return -EFAULT;
1075
1076        err = 0;
1077        err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
1078        err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
1079        err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
1080        err |= __put_user(r.ru_stime.tv_usec, &ur->ru_stime.tv_usec);
1081        err |= __put_user(r.ru_maxrss, &ur->ru_maxrss);
1082        err |= __put_user(r.ru_ixrss, &ur->ru_ixrss);
1083        err |= __put_user(r.ru_idrss, &ur->ru_idrss);
1084        err |= __put_user(r.ru_isrss, &ur->ru_isrss);
1085        err |= __put_user(r.ru_minflt, &ur->ru_minflt);
1086        err |= __put_user(r.ru_majflt, &ur->ru_majflt);
1087        err |= __put_user(r.ru_nswap, &ur->ru_nswap);
1088        err |= __put_user(r.ru_inblock, &ur->ru_inblock);
1089        err |= __put_user(r.ru_oublock, &ur->ru_oublock);
1090        err |= __put_user(r.ru_msgsnd, &ur->ru_msgsnd);
1091        err |= __put_user(r.ru_msgrcv, &ur->ru_msgrcv);
1092        err |= __put_user(r.ru_nsignals, &ur->ru_nsignals);
1093        err |= __put_user(r.ru_nvcsw, &ur->ru_nvcsw);
1094        err |= __put_user(r.ru_nivcsw, &ur->ru_nivcsw);
1095
1096        return err ? err : ret;
1097}
1098
1099/*
1100 * I don't know what the parameters are: the first one
1101 * seems to be a timeval pointer, and I suspect the second
1102 * one is the time remaining.. Ho humm.. No documentation.
1103 */
1104asmlinkage int
1105osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remain)
1106{
1107        struct timeval tmp;
1108        unsigned long ticks;
1109
1110        if (get_tv32(&tmp, sleep))
1111                goto fault;
1112
1113        ticks = timeval_to_jiffies(&tmp);
1114
1115        ticks = schedule_timeout_interruptible(ticks);
1116
1117        if (remain) {
1118                jiffies_to_timeval(ticks, &tmp);
1119                if (put_tv32(remain, &tmp))
1120                        goto fault;
1121        }
1122        
1123        return 0;
1124 fault:
1125        return -EFAULT;
1126}
1127
1128
1129struct timex32 {
1130        unsigned int modes;     /* mode selector */
1131        long offset;            /* time offset (usec) */
1132        long freq;              /* frequency offset (scaled ppm) */
1133        long maxerror;          /* maximum error (usec) */
1134        long esterror;          /* estimated error (usec) */
1135        int status;             /* clock command/status */
1136        long constant;          /* pll time constant */
1137        long precision;         /* clock precision (usec) (read only) */
1138        long tolerance;         /* clock frequency tolerance (ppm)
1139                                 * (read only)
1140                                 */
1141        struct timeval32 time;  /* (read only) */
1142        long tick;              /* (modified) usecs between clock ticks */
1143
1144        long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
1145        long jitter;            /* pps jitter (us) (ro) */
1146        int shift;              /* interval duration (s) (shift) (ro) */
1147        long stabil;            /* pps stability (scaled ppm) (ro) */
1148        long jitcnt;            /* jitter limit exceeded (ro) */
1149        long calcnt;            /* calibration intervals (ro) */
1150        long errcnt;            /* calibration errors (ro) */
1151        long stbcnt;            /* stability limit exceeded (ro) */
1152
1153        int  :32; int  :32; int  :32; int  :32;
1154        int  :32; int  :32; int  :32; int  :32;
1155        int  :32; int  :32; int  :32; int  :32;
1156};
1157
1158asmlinkage int
1159sys_old_adjtimex(struct timex32 __user *txc_p)
1160{
1161        struct timex txc;
1162        int ret;
1163
1164        /* copy relevant bits of struct timex. */
1165        if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
1166            copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - 
1167                           offsetof(struct timex32, time)))
1168          return -EFAULT;
1169
1170        ret = do_adjtimex(&txc);        
1171        if (ret < 0)
1172          return ret;
1173        
1174        /* copy back to timex32 */
1175        if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
1176            (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - 
1177                          offsetof(struct timex32, tick))) ||
1178            (put_tv32(&txc_p->time, &txc.time)))
1179          return -EFAULT;
1180
1181        return ret;
1182}
1183
1184/* Get an address range which is currently unmapped.  Similar to the
1185   generic version except that we know how to honor ADDR_LIMIT_32BIT.  */
1186
1187static unsigned long
1188arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
1189                         unsigned long limit)
1190{
1191        struct vm_area_struct *vma = find_vma(current->mm, addr);
1192
1193        while (1) {
1194                /* At this point:  (!vma || addr < vma->vm_end). */
1195                if (limit - len < addr)
1196                        return -ENOMEM;
1197                if (!vma || addr + len <= vma->vm_start)
1198                        return addr;
1199                addr = vma->vm_end;
1200                vma = vma->vm_next;
1201        }
1202}
1203
1204unsigned long
1205arch_get_unmapped_area(struct file *filp, unsigned long addr,
1206                       unsigned long len, unsigned long pgoff,
1207                       unsigned long flags)
1208{
1209        unsigned long limit;
1210
1211        /* "32 bit" actually means 31 bit, since pointers sign extend.  */
1212        if (current->personality & ADDR_LIMIT_32BIT)
1213                limit = 0x80000000;
1214        else
1215                limit = TASK_SIZE;
1216
1217        if (len > limit)
1218                return -ENOMEM;
1219
1220        if (flags & MAP_FIXED)
1221                return addr;
1222
1223        /* First, see if the given suggestion fits.
1224
1225           The OSF/1 loader (/sbin/loader) relies on us returning an
1226           address larger than the requested if one exists, which is
1227           a terribly broken way to program.
1228
1229           That said, I can see the use in being able to suggest not
1230           merely specific addresses, but regions of memory -- perhaps
1231           this feature should be incorporated into all ports?  */
1232
1233        if (addr) {
1234                addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit);
1235                if (addr != (unsigned long) -ENOMEM)
1236                        return addr;
1237        }
1238
1239        /* Next, try allocating at TASK_UNMAPPED_BASE.  */
1240        addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE),
1241                                         len, limit);
1242        if (addr != (unsigned long) -ENOMEM)
1243                return addr;
1244
1245        /* Finally, try allocating in low memory.  */
1246        addr = arch_get_unmapped_area_1 (PAGE_SIZE, len, limit);
1247
1248        return addr;
1249}
1250
1251#ifdef CONFIG_OSF4_COMPAT
1252
1253/* Clear top 32 bits of iov_len in the user's buffer for
1254   compatibility with old versions of OSF/1 where iov_len
1255   was defined as int. */
1256static int
1257osf_fix_iov_len(const struct iovec __user *iov, unsigned long count)
1258{
1259        unsigned long i;
1260
1261        for (i = 0 ; i < count ; i++) {
1262                int __user *iov_len_high = (int __user *)&iov[i].iov_len + 1;
1263
1264                if (put_user(0, iov_len_high))
1265                        return -EFAULT;
1266        }
1267        return 0;
1268}
1269
1270asmlinkage ssize_t
1271osf_readv(unsigned long fd, const struct iovec __user * vector, unsigned long count)
1272{
1273        if (unlikely(personality(current->personality) == PER_OSF4))
1274                if (osf_fix_iov_len(vector, count))
1275                        return -EFAULT;
1276        return sys_readv(fd, vector, count);
1277}
1278
1279asmlinkage ssize_t
1280osf_writev(unsigned long fd, const struct iovec __user * vector, unsigned long count)
1281{
1282        if (unlikely(personality(current->personality) == PER_OSF4))
1283                if (osf_fix_iov_len(vector, count))
1284                        return -EFAULT;
1285        return sys_writev(fd, vector, count);
1286}
1287
1288#endif
1289
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.