root/arch/alpha/kernel/osf_sys.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. osf_filldir
  2. osf_getdirentries
  3. sys_madvise
  4. sys_getxuid
  5. sys_getxgid
  6. sys_getxpid
  7. osf_mmap
  8. osf_statfs
  9. osf_fstatfs
  10. getdev
  11. putdev
  12. osf_ufs_mount
  13. osf_cdfs_mount
  14. osf_procfs_mount
  15. osf_mount
  16. osf_umount
  17. osf_usleep_thread
  18. osf_utsname
  19. osf_swapon
  20. sys_getpagesize
  21. sys_getdtablesize
  22. sys_pipe
  23. osf_getdomainname
  24. osf_shmat
  25. osf_proplist_syscall
  26. alpha_create_module
  27. osf_getsysinfo
  28. osf_setsysinfo

   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/stddef.h>
  18 #include <linux/unistd.h>
  19 #include <linux/ptrace.h>
  20 #include <linux/malloc.h>
  21 #include <linux/ldt.h>
  22 #include <linux/user.h>
  23 #include <linux/a.out.h>
  24 #include <linux/utsname.h>
  25 #include <linux/time.h>
  26 #include <linux/major.h>
  27 #include <linux/stat.h>
  28 #include <linux/mman.h>
  29 #include <linux/shm.h>
  30 
  31 #include <asm/fpu.h>
  32 #include <asm/io.h>
  33 #include <asm/segment.h>
  34 #include <asm/system.h>
  35 
  36 extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
  37 extern int do_pipe(int *);
  38 
  39 extern struct file_operations * get_blkfops(unsigned int);
  40 extern struct file_operations * get_chrfops(unsigned int);
  41 
  42 extern kdev_t get_unnamed_dev(void);
  43 extern void put_unnamed_dev(kdev_t);
  44 
  45 extern asmlinkage int sys_umount(char *);
  46 extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
  47 
  48 /*
  49  * OSF/1 directory handling functions...
  50  *
  51  * The "getdents()" interface is much more sane: the "basep" stuff is
  52  * braindamage (it can't really handle filesystems where the directory
  53  * offset differences aren't the same as "d_reclen").
  54  */
  55 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
  56 #define ROUND_UP(x) (((x)+3) & ~3)
  57 
  58 struct osf_dirent {
  59         unsigned int    d_ino;
  60         unsigned short  d_reclen;
  61         unsigned short  d_namlen;
  62         char            d_name[1];
  63 };
  64 
  65 struct osf_dirent_callback {
  66         struct osf_dirent * dirent;
  67         long *basep;
  68         int count;
  69         int error;
  70 };
  71 
  72 static int osf_filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         struct osf_dirent * dirent;
  75         struct osf_dirent_callback * buf = (struct osf_dirent_callback *) __buf;
  76         int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
  77 
  78         buf->error = -EINVAL;           /* unly used if we fail */
  79         if (reclen > buf->count)
  80                 return -EINVAL;
  81         if (buf->basep) {
  82                 put_user(offset, buf->basep);
  83                 buf->basep = NULL;
  84         }
  85         dirent = buf->dirent;
  86         put_user(ino, &dirent->d_ino);
  87         put_user(namlen, &dirent->d_namlen);
  88         put_user(reclen, &dirent->d_reclen);
  89         memcpy_tofs(dirent->d_name, name, namlen);
  90         put_fs_byte(0, dirent->d_name + namlen);
  91         ((char *) dirent) += reclen;
  92         buf->dirent = dirent;
  93         buf->count -= reclen;
  94         return 0;
  95 }
  96 
  97 asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent * dirent,
     /* [previous][next][first][last][top][bottom][index][help] */
  98         unsigned int count, long *basep)
  99 {
 100         int error;
 101         struct file * file;
 102         struct osf_dirent_callback buf;
 103 
 104         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 105                 return -EBADF;
 106         if (!file->f_op || !file->f_op->readdir)
 107                 return -ENOTDIR;
 108         error = verify_area(VERIFY_WRITE, dirent, count);
 109         if (error)
 110                 return error;
 111         if (basep) {
 112                 error = verify_area(VERIFY_WRITE, basep, sizeof(long));
 113                 if (error)
 114                         return error;
 115         }
 116         buf.dirent = dirent;
 117         buf.basep = basep;
 118         buf.count = count;
 119         buf.error = 0;
 120         error = file->f_op->readdir(file->f_inode, file, &buf, osf_filldir);
 121         if (error < 0)
 122                 return error;
 123         if (count == buf.count)
 124                 return buf.error;
 125         return count - buf.count;
 126 }
 127 
 128 /*
 129  * Heh. As documented by DEC..
 130  */
 131 asmlinkage unsigned long sys_madvise(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133         return 0;
 134 }
 135 
 136 asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5,
     /* [previous][next][first][last][top][bottom][index][help] */
 137         struct pt_regs regs)
 138 {
 139         (&regs)->r20 = current->euid;
 140         return current->uid;
 141 }
 142 
 143 asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5,
     /* [previous][next][first][last][top][bottom][index][help] */
 144         struct pt_regs regs)
 145 {
 146         (&regs)->r20 = current->egid;
 147         return current->gid;
 148 }
 149 
 150 asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5,
     /* [previous][next][first][last][top][bottom][index][help] */
 151         struct pt_regs regs)
 152 {
 153         (&regs)->r20 = current->p_opptr->pid;
 154         return current->pid;
 155 }
 156 
 157 asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
     /* [previous][next][first][last][top][bottom][index][help] */
 158         unsigned long prot, unsigned long flags, unsigned long fd,
 159         unsigned long off)
 160 {
 161         struct file * file = NULL;
 162 
 163         if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED))
 164                 printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags);
 165         if (!(flags & MAP_ANONYMOUS)) {
 166                 if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 167                         return -EBADF;
 168         }
 169         return do_mmap(file, addr, len, prot, flags, off);
 170 }
 171 
 172 asmlinkage int osf_statfs(char * path, struct statfs * buffer, unsigned long bufsiz)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174         struct inode * inode;
 175         int retval;
 176 
 177         if (bufsiz > sizeof(struct statfs))
 178                 bufsiz = sizeof(struct statfs);
 179         retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
 180         if (retval)
 181                 return retval;
 182         retval = namei(path, &inode);
 183         if (retval)
 184                 return retval;
 185         if (!inode->i_sb->s_op->statfs) {
 186                 iput(inode);
 187                 return -ENOSYS;
 188         }
 189         inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz);
 190         iput(inode);
 191         return 0;
 192 }
 193 
 194 asmlinkage int osf_fstatfs(unsigned long fd, struct statfs * buffer, unsigned long bufsiz)
     /* [previous][next][first][last][top][bottom][index][help] */
 195 {
 196         struct file * file;
 197         struct inode * inode;
 198         int retval;
 199 
 200         retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
 201         if (retval)
 202                 return retval;
 203         if (bufsiz > sizeof(struct statfs))
 204                 bufsiz = sizeof(struct statfs);
 205         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 206                 return -EBADF;
 207         if (!(inode = file->f_inode))
 208                 return -ENOENT;
 209         if (!inode->i_sb->s_op->statfs)
 210                 return -ENOSYS;
 211         inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz);
 212         return 0;
 213 }
 214 
 215 /*
 216  * Uhh.. OSF/1 mount parameters aren't exactly obvious..
 217  *
 218  * Although to be frank, neither are the native Linux/i386 ones..
 219  */
 220 struct ufs_args {
 221         char * devname;
 222         int flags;
 223         uid_t exroot;
 224 };
 225 
 226 struct cdfs_args {
 227         char * devname;
 228         int flags;
 229         uid_t exroot;
 230 /*
 231  * this has lots more here, which linux handles with the option block
 232  * but I'm too lazy to do the translation into ascii..
 233  */
 234 };
 235 
 236 struct procfs_args {
 237         char * devname;
 238         int flags;
 239         uid_t exroot;
 240 };
 241 
 242 static int getdev(const char * name, int rdonly, struct inode ** ino)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244         kdev_t dev;
 245         struct inode * inode;
 246         struct file_operations * fops;
 247         int retval;
 248 
 249         retval = namei(name, &inode);
 250         if (retval)
 251                 return retval;
 252         if (!S_ISBLK(inode->i_mode)) {
 253                 iput(inode);
 254                 return -ENOTBLK;
 255         }
 256         if (IS_NODEV(inode)) {
 257                 iput(inode);
 258                 return -EACCES;
 259         }
 260         dev = inode->i_rdev;
 261         if (MAJOR(dev) >= MAX_BLKDEV) {
 262                 iput(inode);
 263                 return -ENXIO;
 264         }
 265         fops = get_blkfops(MAJOR(dev));
 266         if (!fops) {
 267                 iput(inode);
 268                 return -ENODEV;
 269         }
 270         if (fops->open) {
 271                 struct file dummy;
 272                 memset(&dummy, 0, sizeof(dummy));
 273                 dummy.f_inode = inode;
 274                 dummy.f_mode = rdonly ? 1 : 3;
 275                 retval = fops->open(inode, &dummy);
 276                 if (retval) {
 277                         iput(inode);
 278                         return retval;
 279                 }
 280         }
 281         *ino = inode;
 282         return 0;
 283 }
 284 
 285 static void putdev(struct inode * inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 286 {
 287         struct file_operations * fops;
 288 
 289         fops = get_blkfops(MAJOR(inode->i_rdev));
 290         if (fops->release)
 291                 fops->release(inode, NULL);
 292 }
 293 
 294 /*
 295  * We can't actually handle ufs yet, so we translate UFS mounts to
 296  * ext2fs mounts... I wouldn't mind a USF filesystem, but the UFS
 297  * layout is so braindead it's a major headache doing it..
 298  */
 299 static int osf_ufs_mount(char * dirname, struct ufs_args * args, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301         int retval;
 302         struct inode * inode;
 303         struct cdfs_args tmp;
 304 
 305         retval = verify_area(VERIFY_READ, args, sizeof(*args));
 306         if (retval)
 307                 return retval;
 308         memcpy_fromfs(&tmp, args, sizeof(tmp));
 309         retval = getdev(tmp.devname, 0, &inode);
 310         if (retval)
 311                 return retval;
 312         retval = do_mount(inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL);
 313         if (retval)
 314                 putdev(inode);
 315         iput(inode);
 316         return retval;
 317 }
 318 
 319 static int osf_cdfs_mount(char * dirname, struct cdfs_args * args, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321         int retval;
 322         struct inode * inode;
 323         struct cdfs_args tmp;
 324 
 325         retval = verify_area(VERIFY_READ, args, sizeof(*args));
 326         if (retval)
 327                 return retval;
 328         memcpy_fromfs(&tmp, args, sizeof(tmp));
 329         retval = getdev(tmp.devname, 1, &inode);
 330         if (retval)
 331                 return retval;
 332         retval = do_mount(inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL);
 333         if (retval)
 334                 putdev(inode);
 335         iput(inode);
 336         return retval;
 337 }
 338 
 339 static int osf_procfs_mount(char * dirname, struct procfs_args * args, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 340 {
 341         kdev_t dev;
 342         int retval;
 343         struct procfs_args tmp;
 344 
 345         retval = verify_area(VERIFY_READ, args, sizeof(*args));
 346         if (retval)
 347                 return retval;
 348         memcpy_fromfs(&tmp, args, sizeof(tmp));
 349         dev = get_unnamed_dev();
 350         if (!dev)
 351                 return -ENODEV;
 352         retval = do_mount(dev, "", dirname, "proc", flags, NULL);
 353         if (retval)
 354                 put_unnamed_dev(dev);
 355         return retval;
 356 }
 357 
 358 asmlinkage int osf_mount(unsigned long typenr, char * path, int flag, void * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 359 {
 360         int retval;
 361 
 362         retval = -EINVAL;
 363         switch (typenr) {
 364                 case 1:
 365                         retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
 366                         break;
 367                 case 6:
 368                         retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag);
 369                         break;
 370                 case 9:
 371                         retval = osf_procfs_mount(path, (struct procfs_args *) data, flag);
 372                         break;
 373                 default:
 374                         printk("osf_mount(%ld, %x)\n", typenr, flag);
 375         }
 376         return retval;
 377 }
 378 
 379 asmlinkage int osf_umount(char * path, int flag)
     /* [previous][next][first][last][top][bottom][index][help] */
 380 {
 381         return sys_umount(path);
 382 }
 383 
 384 /*
 385  * I don't know what the parameters are: the first one
 386  * seems to be a timeval pointer, and I suspect the second
 387  * one is the time remaining.. Ho humm.. No documentation.
 388  */
 389 asmlinkage int osf_usleep_thread(struct timeval * sleep, struct timeval * remain)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391         struct timeval tmp;
 392         unsigned long ticks;
 393         int retval;
 394 
 395         retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep));
 396         if (retval)
 397                 return retval;
 398         if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain))))
 399                 return retval;
 400         memcpy_fromfs(&tmp, sleep, sizeof(*sleep));
 401         ticks = tmp.tv_usec;
 402         ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
 403         ticks += tmp.tv_sec * HZ;
 404         current->timeout = ticks + jiffies;
 405         current->state = TASK_INTERRUPTIBLE;
 406         schedule();
 407         if (!remain)
 408                 return 0;
 409         ticks = jiffies;
 410         if (ticks < current->timeout)
 411                 ticks = current->timeout - ticks;
 412         else
 413                 ticks = 0;
 414         current->timeout = 0;
 415         tmp.tv_sec = ticks / HZ;
 416         tmp.tv_usec = ticks % HZ;
 417         memcpy_tofs(remain, &tmp, sizeof(*remain));
 418         return 0;
 419 }
 420 
 421 asmlinkage int osf_utsname(char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 422 {
 423         int error = verify_area(VERIFY_WRITE, name, 5*32);
 424         if (error)
 425                 return error;
 426         memcpy_tofs(name +   0, system_utsname.sysname, 32);
 427         memcpy_tofs(name +  32, system_utsname.nodename, 32);
 428         memcpy_tofs(name +  64, system_utsname.release, 32);
 429         memcpy_tofs(name +  96, system_utsname.version, 32);
 430         memcpy_tofs(name + 128, system_utsname.machine, 32);
 431         return 0;
 432 }
 433 
 434 asmlinkage int osf_swapon(const char * path, int flags, int lowat, int hiwat)
     /* [previous][next][first][last][top][bottom][index][help] */
 435 {
 436         /* for now, simply ignore lowat and hiwat... */
 437         return sys_swapon(path, flags);
 438 }
 439 
 440 asmlinkage unsigned long sys_getpagesize(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 441 {
 442         return PAGE_SIZE;
 443 }
 444 
 445 asmlinkage unsigned long sys_getdtablesize(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 446 {
 447         return NR_OPEN;
 448 }
 449 
 450 asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5,
     /* [previous][next][first][last][top][bottom][index][help] */
 451         struct pt_regs regs)
 452 {
 453         int fd[2];
 454         int error;
 455 
 456         error = do_pipe(fd);
 457         if (error)
 458                 return error;
 459         (&regs)->r20 = fd[1];
 460         return fd[0];
 461 }
 462 
 463 /*
 464  * For compatibility with OSF/1 only.  Use utsname(2) instead.
 465  */
 466 asmlinkage int osf_getdomainname(char *name, int namelen)
     /* [previous][next][first][last][top][bottom][index][help] */
 467 {
 468         unsigned len;
 469         int i, error;
 470 
 471         error = verify_area(VERIFY_WRITE, name, namelen);
 472         if (error)
 473                 return error;
 474 
 475         len = namelen;
 476         if (namelen > 32)
 477           len = 32;
 478 
 479         for (i = 0; i < len; ++i) {
 480                 put_user(system_utsname.domainname[i], name + i);
 481                 if (system_utsname.domainname[i] == '\0')
 482                   break;
 483         }
 484         return 0;
 485 }
 486 
 487 
 488 asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490         unsigned long raddr;
 491         int err;
 492 
 493         err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
 494         if (err)
 495                 return err;
 496         /*
 497          * This works because all user-level addresses are
 498          * non-negative longs!
 499          */
 500         return raddr;
 501 }
 502 
 503 
 504 /*
 505  * The following stuff should move into a header file should it ever
 506  * be labeled "officially supported."  Right now, there is just enough
 507  * support to avoid applications (such as tar) printing error
 508  * messages.  The attributes are not really implemented.
 509  */
 510 
 511 /*
 512  * Values for Property list entry flag
 513  */
 514 #define PLE_PROPAGATE_ON_COPY           0x1     /* cp(1) will copy entry
 515                                                    by default */
 516 #define PLE_FLAG_MASK                   0x1     /* Valid flag values */
 517 #define PLE_FLAG_ALL                    -1      /* All flag value */
 518 
 519 struct proplistname_args {
 520         unsigned int    pl_mask;
 521         unsigned int    pl_numnames;
 522         char            **pl_names;
 523 };
 524 
 525 union pl_args {
 526         struct setargs {
 527                 char *path;
 528                 long follow;
 529                 long nbytes;
 530                 char *buf;
 531         } set;
 532         struct fsetargs {
 533                 long fd;
 534                 long nbytes;
 535                 char *buf;
 536         } fset;
 537         struct getargs {
 538                 char *path;
 539                 long follow;
 540                 struct proplistname_args *name_args;
 541                 long nbytes;
 542                 char *buf;
 543                 int *min_buf_size;
 544         } get;
 545         struct fgetargs {
 546                 long fd;
 547                 struct proplistname_args *name_args;
 548                 long nbytes;
 549                 char *buf;
 550                 int *min_buf_size;
 551         } fget;
 552         struct delargs {
 553                 char *path;
 554                 long follow;
 555                 struct proplistname_args *name_args;
 556         } del;
 557         struct fdelargs {
 558                 long fd;
 559                 struct proplistname_args *name_args;
 560         } fdel;
 561 };
 562 
 563 enum pl_code {
 564         PL_SET  = 1,    PL_FSET = 2,
 565         PL_GET  = 3,    PL_FGET = 4,
 566         PL_DEL  = 5,    PL_FDEL = 6
 567 };
 568 
 569 asmlinkage long osf_proplist_syscall (enum pl_code code, union pl_args *args)
     /* [previous][next][first][last][top][bottom][index][help] */
 570 {
 571         long error;
 572         int *min_buf_size_ptr;
 573 
 574         switch (code) {
 575               case PL_SET:
 576                 error = verify_area(VERIFY_READ, &args->set.nbytes,
 577                                     sizeof(args->set.nbytes));
 578                 if (error)
 579                   return error;
 580                 return args->set.nbytes;
 581 
 582               case PL_FSET:
 583                 error = verify_area(VERIFY_READ, &args->fset.nbytes,
 584                                     sizeof(args->fset.nbytes));
 585                 if (error)
 586                   return error;
 587                 return args->fset.nbytes;
 588 
 589               case PL_GET:
 590                 error = verify_area(VERIFY_READ, &args->get.min_buf_size,
 591                                     sizeof(args->get.min_buf_size));
 592                 if (error)
 593                   return error;
 594                 min_buf_size_ptr = get_user(&args->get.min_buf_size);
 595                 error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
 596                                     sizeof(*min_buf_size_ptr));
 597                 if (error)
 598                   return error;
 599                 put_user(0, min_buf_size_ptr);
 600                 return 0;
 601 
 602               case PL_FGET:
 603                 error = verify_area(VERIFY_READ, &args->fget.min_buf_size,
 604                                     sizeof(args->fget.min_buf_size));
 605                 if (error)
 606                   return error;
 607                 min_buf_size_ptr = get_user(&args->fget.min_buf_size);
 608                 error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
 609                                     sizeof(*min_buf_size_ptr));
 610                 if (error)
 611                   return error;
 612                 put_user(0, min_buf_size_ptr);
 613                 return 0;
 614 
 615               case PL_DEL:
 616               case PL_FDEL:
 617                 return 0;
 618 
 619               default:
 620                 return -EOPNOTSUPP;
 621         }
 622 }
 623 
 624 /*
 625  * The Linux kernel isn't good at returning values that look
 626  * like negative longs (they are mistaken as error values).
 627  * Until that is fixed, we need this little workaround for
 628  * create_module() because it's one of the few system calls
 629  * that return kernel addresses (which are negative).
 630  */
 631 asmlinkage unsigned long
 632 alpha_create_module (char * module_name, unsigned long size,
     /* [previous][next][first][last][top][bottom][index][help] */
 633                      int a3, int a4, int a5, int a6,
 634                      struct pt_regs regs)
 635 {
 636         asmlinkage unsigned long sys_create_module (char *, unsigned long);
 637         long retval;
 638 
 639         retval = sys_create_module(module_name, size);
 640         /*
 641          * we get either a module address or an error number,
 642          * and we know the error number is a small negative
 643          * number, while the address is always negative but
 644          * much larger.
 645          */
 646         if (retval + 1000 > 0)
 647           return retval;
 648 
 649         /* tell entry.S:syscall_error that this is NOT an error: */
 650         regs.r0 = 0;
 651         return retval;
 652 }
 653 
 654 
 655 asmlinkage unsigned long
 656 osf_getsysinfo (unsigned long op, void * buffer, unsigned long nbytes,
     /* [previous][next][first][last][top][bottom][index][help] */
 657                 int * start, void *arg)
 658 {
 659     extern unsigned long rdfpcr (void);
 660     unsigned long fpcw;
 661 
 662     switch (op) {
 663       case 45:  /* GSI_IEEE_FP_CONTROL */
 664           /* build and return current fp control word: */
 665           fpcw = current->tss.flags & IEEE_TRAP_ENABLE_MASK;
 666           fpcw |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK;
 667           put_user(fpcw, (unsigned long *) buffer);
 668           return 0;
 669 
 670       case 46:  /* GSI_IEEE_STATE_AT_SIGNAL */
 671           /*
 672            * Not sure anybody will ever use this weird stuff.  These
 673            * ops can be used (under OSF/1) to set the fpcr that should
 674            * be used when a signal handler starts executing.
 675            */
 676           break;
 677 
 678       default:
 679           break;
 680     }
 681     return -EOPNOTSUPP;
 682 }
 683 
 684 
 685 asmlinkage unsigned long
 686 osf_setsysinfo (unsigned long op, void * buffer, unsigned long nbytes,
     /* [previous][next][first][last][top][bottom][index][help] */
 687                 int * start, void *arg)
 688 {
 689     unsigned long fpcw;
 690 
 691     switch (op) {
 692       case 14:  /* SSI_IEEE_FP_CONTROL */
 693           /* update trap enable bits: */
 694           fpcw = get_user((unsigned long *) buffer);
 695           current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK;
 696           current->tss.flags |= (fpcw & IEEE_TRAP_ENABLE_MASK);
 697           return 0;
 698 
 699       case 15:  /* SSI_IEEE_STATE_AT_SIGNAL */
 700       case 16:  /* SSI_IEEE_IGNORE_STATE_AT_SIGNAL */
 701           /*
 702            * Not sure anybody will ever use this weird stuff.  These
 703            * ops can be used (under OSF/1) to set the fpcr that should
 704            * be used when a signal handler starts executing.
 705            */
 706       default:
 707           break;
 708     }
 709     return -EOPNOTSUPP;
 710 }

/* [previous][next][first][last][top][bottom][index][help] */