2.2.0-final
[davej-history.git] / arch / alpha / kernel / osf_sys.c
blob67c08778d2faa4177082fa6070d8776a7759f02c
1 /*
2 * linux/arch/alpha/kernel/osf_sys.c
4 * Copyright (C) 1995 Linus Torvalds
5 */
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..
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/unistd.h>
21 #include <linux/ptrace.h>
22 #include <linux/malloc.h>
23 #include <linux/user.h>
24 #include <linux/a.out.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>
35 #include <asm/fpu.h>
36 #include <asm/io.h>
37 #include <asm/uaccess.h>
38 #include <asm/system.h>
39 #include <asm/sysinfo.h>
41 extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
42 extern int do_pipe(int *);
44 extern struct file_operations *get_blkfops(unsigned int);
45 extern struct file_operations *get_chrfops(unsigned int);
47 extern kdev_t get_unnamed_dev(void);
48 extern void put_unnamed_dev(kdev_t);
50 extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
51 extern asmlinkage unsigned long sys_brk(unsigned long);
54 * Brk needs to return an error. Still support Linux's brk(0) query idiom,
55 * which OSF programs just shouldn't be doing. We're still not quite
56 * identical to OSF as we don't return 0 on success, but doing otherwise
57 * would require changes to libc. Hopefully this is good enough.
59 asmlinkage unsigned long osf_brk(unsigned long brk)
61 unsigned long retval = sys_brk(brk);
62 if (brk && brk != retval)
63 retval = -ENOMEM;
64 return retval;
68 * This is pure guess-work..
70 asmlinkage int osf_set_program_attributes(
71 unsigned long text_start, unsigned long text_len,
72 unsigned long bss_start, unsigned long bss_len)
74 struct mm_struct *mm;
76 lock_kernel();
77 mm = current->mm;
78 mm->end_code = bss_start + bss_len;
79 mm->brk = bss_start + bss_len;
80 printk("set_program_attributes(%lx %lx %lx %lx)\n",
81 text_start, text_len, bss_start, bss_len);
82 unlock_kernel();
83 return 0;
87 * OSF/1 directory handling functions...
89 * The "getdents()" interface is much more sane: the "basep" stuff is
90 * braindamage (it can't really handle filesystems where the directory
91 * offset differences aren't the same as "d_reclen").
93 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
94 #define ROUND_UP(x) (((x)+3) & ~3)
96 struct osf_dirent {
97 unsigned int d_ino;
98 unsigned short d_reclen;
99 unsigned short d_namlen;
100 char d_name[1];
103 struct osf_dirent_callback {
104 struct osf_dirent *dirent;
105 long *basep;
106 int count;
107 int error;
110 static int osf_filldir(void *__buf, const char *name, int namlen, off_t offset, ino_t ino)
112 struct osf_dirent *dirent;
113 struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
114 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
116 buf->error = -EINVAL; /* only used if we fail */
117 if (reclen > buf->count)
118 return -EINVAL;
119 if (buf->basep) {
120 put_user(offset, buf->basep);
121 buf->basep = NULL;
123 dirent = buf->dirent;
124 put_user(ino, &dirent->d_ino);
125 put_user(namlen, &dirent->d_namlen);
126 put_user(reclen, &dirent->d_reclen);
127 copy_to_user(dirent->d_name, name, namlen);
128 put_user(0, dirent->d_name + namlen);
129 ((char *) dirent) += reclen;
130 buf->dirent = dirent;
131 buf->count -= reclen;
132 return 0;
135 asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
136 unsigned int count, long *basep)
138 int error;
139 struct file *file;
140 struct inode *inode;
141 struct osf_dirent_callback buf;
143 error = -EBADF;
144 file = fget(fd);
145 if (!file)
146 goto out;
148 buf.dirent = dirent;
149 buf.basep = basep;
150 buf.count = count;
151 buf.error = 0;
153 error = -ENOTDIR;
154 if (!file->f_op || !file->f_op->readdir)
155 goto out_putf;
158 * Get the inode's semaphore to prevent changes
159 * to the directory while we read it.
161 inode = file->f_dentry->d_inode;
162 down(&inode->i_sem);
163 error = file->f_op->readdir(file, &buf, osf_filldir);
164 up(&inode->i_sem);
165 if (error < 0)
166 goto out_putf;
168 error = buf.error;
169 if (count != buf.count)
170 error = count - buf.count;
172 out_putf:
173 fput(file);
174 out:
175 return error;
178 #undef ROUND_UP
179 #undef NAME_OFFSET
182 * Alpha syscall convention has no problem returning negative
183 * values:
185 asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4,
186 int a5, struct pt_regs regs)
188 extern int sys_getpriority(int, int);
189 int prio;
192 * We don't need to acquire the kernel lock here, because
193 * all of these operations are local. sys_getpriority
194 * will get the lock as required..
196 prio = sys_getpriority(which, who);
197 if (prio >= 0) {
198 regs.r0 = 0; /* special return: no errors */
199 prio = 20 - prio;
201 return prio;
206 * Heh. As documented by DEC..
208 asmlinkage unsigned long sys_madvise(void)
210 return 0;
214 * No need to acquire the kernel lock, we're local..
216 asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4,
217 int a5, struct pt_regs regs)
219 struct task_struct * tsk = current;
220 (&regs)->r20 = tsk->euid;
221 return tsk->uid;
224 asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4,
225 int a5, struct pt_regs regs)
227 struct task_struct * tsk = current;
228 (&regs)->r20 = tsk->egid;
229 return tsk->gid;
232 asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4,
233 int a5, struct pt_regs regs)
235 struct task_struct *tsk = current;
238 * This isn't strictly "local" any more and we should actually
239 * acquire the kernel lock. The "p_opptr" pointer might change
240 * if the parent goes away (or due to ptrace). But any race
241 * isn't actually going to matter, as if the parent happens
242 * to change we can happily return either of the pids.
244 (&regs)->r20 = tsk->p_opptr->pid;
245 return tsk->pid;
248 asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
249 unsigned long prot, unsigned long flags, unsigned long fd,
250 unsigned long off)
252 struct file *file = NULL;
253 unsigned long ret = -EBADF;
255 lock_kernel();
256 #if 0
257 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
258 printk("%s: unimplemented OSF mmap flags %04lx\n",
259 current->comm, flags);
260 #endif
261 if (!(flags & MAP_ANONYMOUS)) {
262 file = fget(fd);
263 if (!file)
264 goto out;
266 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
267 ret = do_mmap(file, addr, len, prot, flags, off);
268 if (file)
269 fput(file);
270 out:
271 unlock_kernel();
272 return ret;
277 * The OSF/1 statfs structure is much larger, but this should
278 * match the beginning, at least.
280 struct osf_statfs {
281 short f_type;
282 short f_flags;
283 int f_fsize;
284 int f_bsize;
285 int f_blocks;
286 int f_bfree;
287 int f_bavail;
288 int f_files;
289 int f_ffree;
290 __kernel_fsid_t f_fsid;
291 } *osf_stat;
293 static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz)
295 struct osf_statfs tmp_stat;
297 tmp_stat.f_type = linux_stat->f_type;
298 tmp_stat.f_flags = 0; /* mount flags */
299 /* Linux doesn't provide a "fundamental filesystem block size": */
300 tmp_stat.f_fsize = linux_stat->f_bsize;
301 tmp_stat.f_bsize = linux_stat->f_bsize;
302 tmp_stat.f_blocks = linux_stat->f_blocks;
303 tmp_stat.f_bfree = linux_stat->f_bfree;
304 tmp_stat.f_bavail = linux_stat->f_bavail;
305 tmp_stat.f_files = linux_stat->f_files;
306 tmp_stat.f_ffree = linux_stat->f_ffree;
307 tmp_stat.f_fsid = linux_stat->f_fsid;
308 if (bufsiz > sizeof(tmp_stat))
309 bufsiz = sizeof(tmp_stat);
310 return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
313 static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz)
315 struct statfs linux_stat;
316 struct inode * inode = dentry->d_inode;
317 struct super_block * sb = inode->i_sb;
318 int error;
320 error = -ENOSYS;
321 if (sb->s_op->statfs) {
322 set_fs(KERNEL_DS);
323 error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat));
324 set_fs(USER_DS);
325 if (!error)
326 error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
328 return error;
331 asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz)
333 struct dentry *dentry;
334 int retval;
336 lock_kernel();
337 dentry = namei(path);
338 retval = PTR_ERR(dentry);
339 if (!IS_ERR(dentry)) {
340 retval = do_osf_statfs(dentry, buffer, bufsiz);
341 dput(dentry);
343 unlock_kernel();
344 return retval;
347 asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
349 struct file *file;
350 struct dentry *dentry;
351 int retval;
353 lock_kernel();
354 retval = -EBADF;
355 file = fget(fd);
356 if (!file)
357 goto out;
358 dentry = file->f_dentry;
359 if (dentry)
360 retval = do_osf_statfs(dentry, buffer, bufsiz);
361 fput(file);
362 out:
363 unlock_kernel();
364 return retval;
368 * Uhh.. OSF/1 mount parameters aren't exactly obvious..
370 * Although to be frank, neither are the native Linux/i386 ones..
372 struct ufs_args {
373 char *devname;
374 int flags;
375 uid_t exroot;
378 struct cdfs_args {
379 char *devname;
380 int flags;
381 uid_t exroot;
383 * This has lots more here, which Linux handles with the option block
384 * but I'm too lazy to do the translation into ASCII.
388 struct procfs_args {
389 char *devname;
390 int flags;
391 uid_t exroot;
394 static int getdev(const char *name, int rdonly, struct dentry **dp)
396 kdev_t dev;
397 struct dentry *dentry;
398 struct inode *inode;
399 struct file_operations *fops;
400 int retval;
402 dentry = namei(name);
403 retval = PTR_ERR(dentry);
404 if (IS_ERR(dentry))
405 return retval;
407 retval = -ENOTBLK;
408 inode = dentry->d_inode;
409 if (!S_ISBLK(inode->i_mode))
410 goto out_dput;
412 retval = -EACCES;
413 if (IS_NODEV(inode))
414 goto out_dput;
416 retval = -ENXIO;
417 dev = inode->i_rdev;
418 if (MAJOR(dev) >= MAX_BLKDEV)
419 goto out_dput;
421 retval = -ENODEV;
422 fops = get_blkfops(MAJOR(dev));
423 if (!fops)
424 goto out_dput;
425 if (fops->open) {
426 struct file dummy;
427 memset(&dummy, 0, sizeof(dummy));
428 dummy.f_dentry = dentry;
429 dummy.f_mode = rdonly ? 1 : 3;
430 retval = fops->open(inode, &dummy);
431 if (retval)
432 goto out_dput;
434 *dp = dentry;
435 retval = 0;
436 out:
437 return retval;
439 out_dput:
440 dput(dentry);
441 goto out;
444 static void putdev(struct dentry *dentry)
446 struct file_operations *fops;
448 fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev));
449 if (fops->release)
450 fops->release(dentry->d_inode, NULL);
454 * We can't actually handle ufs yet, so we translate UFS mounts to
455 * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
456 * layout is so braindead it's a major headache doing it.
458 static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
460 int retval;
461 struct dentry *dentry;
462 struct cdfs_args tmp;
464 retval = -EFAULT;
465 if (copy_from_user(&tmp, args, sizeof(tmp)))
466 goto out;
468 retval = getdev(tmp.devname, 0, &dentry);
469 if (retval)
470 goto out;
471 retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname,
472 "ext2", flags, NULL);
473 if (retval)
474 putdev(dentry);
475 dput(dentry);
476 out:
477 return retval;
480 static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
482 int retval;
483 struct dentry * dentry;
484 struct cdfs_args tmp;
486 retval = -EFAULT;
487 if (copy_from_user(&tmp, args, sizeof(tmp)))
488 goto out;
490 retval = getdev(tmp.devname, 1, &dentry);
491 if (retval)
492 goto out;
493 retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname,
494 "iso9660", flags, NULL);
495 if (retval)
496 putdev(dentry);
497 dput(dentry);
498 out:
499 return retval;
502 static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
504 kdev_t dev;
505 int retval;
506 struct procfs_args tmp;
508 if (copy_from_user(&tmp, args, sizeof(tmp)))
509 return -EFAULT;
510 dev = get_unnamed_dev();
511 if (!dev)
512 return -ENODEV;
513 retval = do_mount(dev, "", dirname, "proc", flags, NULL);
514 if (retval)
515 put_unnamed_dev(dev);
516 return retval;
519 asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
521 int retval = -EINVAL;
523 lock_kernel();
524 switch (typenr) {
525 case 1:
526 retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
527 break;
528 case 6:
529 retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag);
530 break;
531 case 9:
532 retval = osf_procfs_mount(path, (struct procfs_args *) data, flag);
533 break;
534 default:
535 printk("osf_mount(%ld, %x)\n", typenr, flag);
537 unlock_kernel();
538 return retval;
541 asmlinkage int osf_utsname(char *name)
543 int error;
545 down(&uts_sem);
546 error = -EFAULT;
547 if (copy_to_user(name + 0, system_utsname.sysname, 32))
548 goto out;
549 if (copy_to_user(name + 32, system_utsname.nodename, 32))
550 goto out;
551 if (copy_to_user(name + 64, system_utsname.release, 32))
552 goto out;
553 if (copy_to_user(name + 96, system_utsname.version, 32))
554 goto out;
555 if (copy_to_user(name + 128, system_utsname.machine, 32))
556 goto out;
558 error = 0;
559 out:
560 up(&uts_sem);
561 return error;
564 asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
566 int ret;
568 /* for now, simply ignore lowat and hiwat... */
569 lock_kernel();
570 ret = sys_swapon(path, flags);
571 unlock_kernel();
572 return ret;
575 asmlinkage unsigned long sys_getpagesize(void)
577 return PAGE_SIZE;
580 asmlinkage unsigned long sys_getdtablesize(void)
582 return NR_OPEN;
585 asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5,
586 struct pt_regs regs)
588 int fd[2];
589 int error;
591 lock_kernel();
592 error = do_pipe(fd);
593 if (error)
594 goto out;
595 (&regs)->r20 = fd[1];
596 error = fd[0];
597 out:
598 unlock_kernel();
599 return error;
603 * For compatibility with OSF/1 only. Use utsname(2) instead.
605 asmlinkage int osf_getdomainname(char *name, int namelen)
607 unsigned len;
608 int i, error;
610 lock_kernel();
611 error = verify_area(VERIFY_WRITE, name, namelen);
612 if (error)
613 goto out;
615 len = namelen;
616 if (namelen > 32)
617 len = 32;
619 down(&uts_sem);
620 for (i = 0; i < len; ++i) {
621 __put_user(system_utsname.domainname[i], name + i);
622 if (system_utsname.domainname[i] == '\0')
623 break;
625 up(&uts_sem);
626 out:
627 unlock_kernel();
628 return error;
632 asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
634 unsigned long raddr;
635 long err;
637 lock_kernel();
638 err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
639 if (err)
640 goto out;
642 * This works because all user-level addresses are
643 * non-negative longs!
645 err = raddr;
646 out:
647 unlock_kernel();
648 return err;
653 * The following stuff should move into a header file should it ever
654 * be labeled "officially supported." Right now, there is just enough
655 * support to avoid applications (such as tar) printing error
656 * messages. The attributes are not really implemented.
660 * Values for Property list entry flag
662 #define PLE_PROPAGATE_ON_COPY 0x1 /* cp(1) will copy entry
663 by default */
664 #define PLE_FLAG_MASK 0x1 /* Valid flag values */
665 #define PLE_FLAG_ALL -1 /* All flag value */
667 struct proplistname_args {
668 unsigned int pl_mask;
669 unsigned int pl_numnames;
670 char **pl_names;
673 union pl_args {
674 struct setargs {
675 char *path;
676 long follow;
677 long nbytes;
678 char *buf;
679 } set;
680 struct fsetargs {
681 long fd;
682 long nbytes;
683 char *buf;
684 } fset;
685 struct getargs {
686 char *path;
687 long follow;
688 struct proplistname_args *name_args;
689 long nbytes;
690 char *buf;
691 int *min_buf_size;
692 } get;
693 struct fgetargs {
694 long fd;
695 struct proplistname_args *name_args;
696 long nbytes;
697 char *buf;
698 int *min_buf_size;
699 } fget;
700 struct delargs {
701 char *path;
702 long follow;
703 struct proplistname_args *name_args;
704 } del;
705 struct fdelargs {
706 long fd;
707 struct proplistname_args *name_args;
708 } fdel;
711 enum pl_code {
712 PL_SET = 1, PL_FSET = 2,
713 PL_GET = 3, PL_FGET = 4,
714 PL_DEL = 5, PL_FDEL = 6
717 asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args)
719 long error;
720 int *min_buf_size_ptr;
722 lock_kernel();
723 switch (code) {
724 case PL_SET:
725 error = verify_area(VERIFY_READ, &args->set.nbytes,
726 sizeof(args->set.nbytes));
727 if (!error)
728 error = args->set.nbytes;
729 break;
730 case PL_FSET:
731 error = verify_area(VERIFY_READ, &args->fset.nbytes,
732 sizeof(args->fset.nbytes));
733 if (!error)
734 error = args->fset.nbytes;
735 break;
736 case PL_GET:
737 get_user(min_buf_size_ptr, &args->get.min_buf_size);
738 error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
739 sizeof(*min_buf_size_ptr));
740 if (!error)
741 put_user(0, min_buf_size_ptr);
742 break;
743 case PL_FGET:
744 get_user(min_buf_size_ptr, &args->fget.min_buf_size);
745 error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
746 sizeof(*min_buf_size_ptr));
747 if (!error)
748 put_user(0, min_buf_size_ptr);
749 break;
750 case PL_DEL:
751 case PL_FDEL:
752 error = 0;
753 break;
754 default:
755 error = -EOPNOTSUPP;
756 break;
758 unlock_kernel();
759 return error;
762 asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
764 unsigned long usp = rdusp();
765 unsigned long oss_sp, oss_os;
766 int error;
768 if (uoss) {
769 oss_sp = current->sas_ss_sp + current->sas_ss_size;
770 oss_os = on_sig_stack(usp);
773 if (uss) {
774 void *ss_sp;
776 error = -EFAULT;
777 if (get_user(ss_sp, &uss->ss_sp))
778 goto out;
780 /* If the current stack was set with sigaltstack, don't
781 swap stacks while we are on it. */
782 error = -EPERM;
783 if (current->sas_ss_sp && on_sig_stack(usp))
784 goto out;
786 /* Since we don't know the extent of the stack, and we don't
787 track onstack-ness, but rather calculate it, we must
788 presume a size. Ho hum this interface is lossy. */
789 current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
790 current->sas_ss_size = SIGSTKSZ;
793 if (uoss) {
794 error = -EFAULT;
795 if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))
796 || __put_user(oss_sp, &uoss->ss_sp)
797 || __put_user(oss_os, &uoss->ss_onstack))
798 goto out;
801 error = 0;
802 out:
803 return error;
807 * The Linux kernel isn't good at returning values that look
808 * like negative longs (they are mistaken as error values).
809 * Until that is fixed, we need this little workaround for
810 * create_module() because it's one of the few system calls
811 * that return kernel addresses (which are negative).
813 asmlinkage unsigned long alpha_create_module(char *module_name, unsigned long size,
814 int a3, int a4, int a5, int a6,
815 struct pt_regs regs)
817 asmlinkage unsigned long sys_create_module(char *, unsigned long);
818 long retval;
820 lock_kernel();
821 retval = sys_create_module(module_name, size);
823 * we get either a module address or an error number,
824 * and we know the error number is a small negative
825 * number, while the address is always negative but
826 * much larger.
828 if (retval + 1000 > 0)
829 goto out;
831 /* tell entry.S:syscall_error that this is NOT an error: */
832 regs.r0 = 0;
833 out:
834 unlock_kernel();
835 return retval;
838 asmlinkage long osf_sysinfo(int command, char *buf, long count)
840 static char * sysinfo_table[] = {
841 system_utsname.sysname,
842 system_utsname.nodename,
843 system_utsname.release,
844 system_utsname.version,
845 system_utsname.machine,
846 "alpha", /* instruction set architecture */
847 "dummy", /* hardware serial number */
848 "dummy", /* hardware manufacturer */
849 "dummy", /* secure RPC domain */
851 unsigned long offset;
852 char *res;
853 long len, err = -EINVAL;
855 lock_kernel();
856 offset = command-1;
857 if (offset >= sizeof(sysinfo_table)/sizeof(char *)) {
858 /* Digital UNIX has a few unpublished interfaces here */
859 printk("sysinfo(%d)", command);
860 goto out;
863 down(&uts_sem);
864 res = sysinfo_table[offset];
865 len = strlen(res)+1;
866 if (len > count)
867 len = count;
868 if (copy_to_user(buf, res, len))
869 err = -EFAULT;
870 else
871 err = 0;
872 up(&uts_sem);
873 out:
874 unlock_kernel();
875 return err;
878 asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
879 unsigned long nbytes,
880 int *start, void *arg)
882 unsigned long w;
884 switch (op) {
885 case GSI_IEEE_FP_CONTROL:
886 /* Return current software fp control & status bits. */
887 w = current->tss.flags & IEEE_SW_MASK;
888 if (put_user(w, (unsigned long *) buffer))
889 return -EFAULT;
890 return 0;
892 case GSI_IEEE_STATE_AT_SIGNAL:
894 * Not sure anybody will ever use this weird stuff. These
895 * ops can be used (under OSF/1) to set the fpcr that should
896 * be used when a signal handler starts executing.
898 break;
900 case GSI_UACPROC:
901 w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
902 if (put_user(w, (unsigned int *)buffer))
903 return -EFAULT;
904 return 0;
906 default:
907 break;
910 return -EOPNOTSUPP;
913 asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
914 unsigned long nbytes,
915 int *start, void *arg)
917 switch (op) {
918 case SSI_IEEE_FP_CONTROL: {
919 unsigned long swcr, fpcr;
922 * Alpha Architecture Handbook 4.7.7.3:
923 * To be fully IEEE compiant, we must track the current IEEE
924 * exception state in software, because spurrious bits can be
925 * set in the trap shadow of a software-complete insn.
928 /* Update softare trap enable bits. */
929 if (get_user(swcr, (unsigned long *)buffer))
930 return -EFAULT;
931 current->tss.flags &= ~IEEE_SW_MASK;
932 current->tss.flags |= swcr & IEEE_SW_MASK;
934 /* Update the real fpcr. For exceptions that are disabled in
935 software but have not been seen, enable the exception in
936 hardware so that we can update our software status mask. */
937 fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
938 fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
939 wrfpcr(fpcr);
941 return 0;
944 case SSI_IEEE_STATE_AT_SIGNAL:
945 case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
947 * Not sure anybody will ever use this weird stuff. These
948 * ops can be used (under OSF/1) to set the fpcr that should
949 * be used when a signal handler starts executing.
951 break;
953 case SSI_NVPAIRS: {
954 unsigned long v, w, i;
956 for (i = 0; i < nbytes; ++i) {
957 if (get_user(v, 2*i + (unsigned int *)buffer))
958 return -EFAULT;
959 if (get_user(w, 2*i + 1 + (unsigned int *)buffer))
960 return -EFAULT;
961 switch (v) {
962 case SSIN_UACPROC:
963 current->tss.flags &=
964 ~(UAC_BITMASK << UAC_SHIFT);
965 current->tss.flags |=
966 (w & UAC_BITMASK) << UAC_SHIFT;
967 break;
969 default:
970 return -EOPNOTSUPP;
973 return 0;
976 default:
977 break;
980 return -EOPNOTSUPP;
983 /* Translations due to the fact that OSF's time_t is an int. Which
984 affects all sorts of things, like timeval and itimerval. */
986 extern struct timezone sys_tz;
987 extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
988 extern int do_getitimer(int which, struct itimerval *value);
989 extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
990 asmlinkage int sys_utimes(char *, struct timeval *);
991 extern int sys_wait4(pid_t, int *, int, struct rusage *);
992 extern int do_adjtimex(struct timex *);
994 struct timeval32
996 int tv_sec, tv_usec;
999 struct itimerval32
1001 struct timeval32 it_interval;
1002 struct timeval32 it_value;
1005 static inline long get_tv32(struct timeval *o, struct timeval32 *i)
1007 return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
1008 (__get_user(o->tv_sec, &i->tv_sec) |
1009 __get_user(o->tv_usec, &i->tv_usec)));
1012 static inline long put_tv32(struct timeval32 *o, struct timeval *i)
1014 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
1015 (__put_user(i->tv_sec, &o->tv_sec) |
1016 __put_user(i->tv_usec, &o->tv_usec)));
1019 static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
1021 return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
1022 (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
1023 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
1024 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
1025 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
1028 static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
1030 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
1031 (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
1032 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
1033 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
1034 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
1037 asmlinkage int osf_gettimeofday(struct timeval32 *tv, struct timezone *tz)
1039 if (tv) {
1040 struct timeval ktv;
1041 do_gettimeofday(&ktv);
1042 if (put_tv32(tv, &ktv))
1043 return -EFAULT;
1045 if (tz) {
1046 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
1047 return -EFAULT;
1049 return 0;
1052 asmlinkage int osf_settimeofday(struct timeval32 *tv, struct timezone *tz)
1054 struct timeval ktv;
1055 struct timezone ktz;
1057 if (tv) {
1058 if (get_tv32(&ktv, tv))
1059 return -EFAULT;
1061 if (tz) {
1062 if (copy_from_user(&ktz, tz, sizeof(*tz)))
1063 return -EFAULT;
1066 return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
1069 asmlinkage int osf_getitimer(int which, struct itimerval32 *it)
1071 struct itimerval kit;
1072 int error;
1074 error = do_getitimer(which, &kit);
1075 if (!error && put_it32(it, &kit))
1076 error = -EFAULT;
1078 return error;
1081 asmlinkage int osf_setitimer(int which, struct itimerval32 *in,
1082 struct itimerval32 *out)
1084 struct itimerval kin, kout;
1085 int error;
1087 if (in) {
1088 if (get_it32(&kin, in))
1089 return -EFAULT;
1090 } else
1091 memset(&kin, 0, sizeof(kin));
1093 error = do_setitimer(which, &kin, out ? &kout : NULL);
1094 if (error || !out)
1095 return error;
1097 if (put_it32(out, &kout))
1098 return -EFAULT;
1100 return 0;
1104 asmlinkage int osf_utimes(const char *filename, struct timeval32 *tvs)
1106 char *kfilename;
1107 struct timeval ktvs[2];
1108 mm_segment_t old_fs;
1109 int ret;
1111 kfilename = getname(filename);
1112 if (IS_ERR(kfilename))
1113 return PTR_ERR(kfilename);
1115 if (tvs) {
1116 if (get_tv32(&ktvs[0], &tvs[0]) ||
1117 get_tv32(&ktvs[1], &tvs[1]))
1118 return -EFAULT;
1121 old_fs = get_fs();
1122 set_fs(KERNEL_DS);
1123 ret = sys_utimes(kfilename, tvs ? ktvs : 0);
1124 set_fs(old_fs);
1126 putname(kfilename);
1128 return ret;
1131 #define MAX_SELECT_SECONDS \
1132 ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
1134 asmlinkage int
1135 osf_select(int n, fd_set *inp, fd_set *outp, fd_set *exp,
1136 struct timeval32 *tvp)
1138 fd_set_bits fds;
1139 char *bits;
1140 size_t size;
1141 unsigned long timeout;
1142 int ret;
1144 timeout = MAX_SCHEDULE_TIMEOUT;
1145 if (tvp) {
1146 time_t sec, usec;
1148 if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
1149 || (ret = __get_user(sec, &tvp->tv_sec))
1150 || (ret = __get_user(usec, &tvp->tv_usec)))
1151 goto out_nofds;
1153 ret = -EINVAL;
1154 if (sec < 0 || usec < 0)
1155 goto out_nofds;
1157 if ((unsigned long) sec < MAX_SELECT_SECONDS) {
1158 timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
1159 timeout += sec * (unsigned long) HZ;
1163 ret = -EINVAL;
1164 if (n < 0 || n > KFDS_NR)
1165 goto out_nofds;
1168 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
1169 * since we used fdset we need to allocate memory in units of
1170 * long-words.
1172 ret = -ENOMEM;
1173 size = FDS_BYTES(n);
1174 bits = kmalloc(6 * size, GFP_KERNEL);
1175 if (!bits)
1176 goto out_nofds;
1177 fds.in = (unsigned long *) bits;
1178 fds.out = (unsigned long *) (bits + size);
1179 fds.ex = (unsigned long *) (bits + 2*size);
1180 fds.res_in = (unsigned long *) (bits + 3*size);
1181 fds.res_out = (unsigned long *) (bits + 4*size);
1182 fds.res_ex = (unsigned long *) (bits + 5*size);
1184 if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) ||
1185 (ret = get_fd_set(n, outp->fds_bits, fds.out)) ||
1186 (ret = get_fd_set(n, exp->fds_bits, fds.ex)))
1187 goto out;
1188 zero_fd_set(n, fds.res_in);
1189 zero_fd_set(n, fds.res_out);
1190 zero_fd_set(n, fds.res_ex);
1192 ret = do_select(n, &fds, &timeout);
1194 /* OSF does not copy back the remaining time. */
1196 if (ret < 0)
1197 goto out;
1198 if (!ret) {
1199 ret = -ERESTARTNOHAND;
1200 if (signal_pending(current))
1201 goto out;
1202 ret = 0;
1205 set_fd_set(n, inp->fds_bits, fds.res_in);
1206 set_fd_set(n, outp->fds_bits, fds.res_out);
1207 set_fd_set(n, exp->fds_bits, fds.res_ex);
1209 out:
1210 kfree(bits);
1211 out_nofds:
1212 return ret;
1215 struct rusage32 {
1216 struct timeval32 ru_utime; /* user time used */
1217 struct timeval32 ru_stime; /* system time used */
1218 long ru_maxrss; /* maximum resident set size */
1219 long ru_ixrss; /* integral shared memory size */
1220 long ru_idrss; /* integral unshared data size */
1221 long ru_isrss; /* integral unshared stack size */
1222 long ru_minflt; /* page reclaims */
1223 long ru_majflt; /* page faults */
1224 long ru_nswap; /* swaps */
1225 long ru_inblock; /* block input operations */
1226 long ru_oublock; /* block output operations */
1227 long ru_msgsnd; /* messages sent */
1228 long ru_msgrcv; /* messages received */
1229 long ru_nsignals; /* signals received */
1230 long ru_nvcsw; /* voluntary context switches */
1231 long ru_nivcsw; /* involuntary " */
1234 asmlinkage int osf_getrusage(int who, struct rusage32 *ru)
1236 struct rusage32 r;
1238 if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
1239 return -EINVAL;
1241 memset(&r, 0, sizeof(r));
1242 switch (who) {
1243 case RUSAGE_SELF:
1244 r.ru_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
1245 r.ru_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
1246 r.ru_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
1247 r.ru_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
1248 r.ru_minflt = current->min_flt;
1249 r.ru_majflt = current->maj_flt;
1250 r.ru_nswap = current->nswap;
1251 break;
1252 case RUSAGE_CHILDREN:
1253 r.ru_utime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
1254 r.ru_utime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
1255 r.ru_stime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
1256 r.ru_stime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
1257 r.ru_minflt = current->cmin_flt;
1258 r.ru_majflt = current->cmaj_flt;
1259 r.ru_nswap = current->cnswap;
1260 break;
1261 default:
1262 r.ru_utime.tv_sec = CT_TO_SECS(current->times.tms_utime +
1263 current->times.tms_cutime);
1264 r.ru_utime.tv_usec = CT_TO_USECS(current->times.tms_utime +
1265 current->times.tms_cutime);
1266 r.ru_stime.tv_sec = CT_TO_SECS(current->times.tms_stime +
1267 current->times.tms_cstime);
1268 r.ru_stime.tv_usec = CT_TO_USECS(current->times.tms_stime +
1269 current->times.tms_cstime);
1270 r.ru_minflt = current->min_flt + current->cmin_flt;
1271 r.ru_majflt = current->maj_flt + current->cmaj_flt;
1272 r.ru_nswap = current->nswap + current->cnswap;
1273 break;
1276 return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
1279 asmlinkage int osf_wait4(pid_t pid, int *ustatus, int options,
1280 struct rusage32 *ur)
1282 if (!ur) {
1283 return sys_wait4(pid, ustatus, options, NULL);
1284 } else {
1285 struct rusage r;
1286 int ret, status;
1287 mm_segment_t old_fs = get_fs();
1289 set_fs (KERNEL_DS);
1290 ret = sys_wait4(pid, &status, options, &r);
1291 set_fs (old_fs);
1293 if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
1294 return -EFAULT;
1295 __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
1296 __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
1297 __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
1298 __put_user(r.ru_stime.tv_usec, &ur->ru_stime.tv_usec);
1299 __put_user(r.ru_maxrss, &ur->ru_maxrss);
1300 __put_user(r.ru_ixrss, &ur->ru_ixrss);
1301 __put_user(r.ru_idrss, &ur->ru_idrss);
1302 __put_user(r.ru_isrss, &ur->ru_isrss);
1303 __put_user(r.ru_minflt, &ur->ru_minflt);
1304 __put_user(r.ru_majflt, &ur->ru_majflt);
1305 __put_user(r.ru_nswap, &ur->ru_nswap);
1306 __put_user(r.ru_inblock, &ur->ru_inblock);
1307 __put_user(r.ru_oublock, &ur->ru_oublock);
1308 __put_user(r.ru_msgsnd, &ur->ru_msgsnd);
1309 __put_user(r.ru_msgrcv, &ur->ru_msgrcv);
1310 __put_user(r.ru_nsignals, &ur->ru_nsignals);
1311 __put_user(r.ru_nvcsw, &ur->ru_nvcsw);
1312 if (__put_user(r.ru_nivcsw, &ur->ru_nivcsw))
1313 return -EFAULT;
1315 if (ustatus && put_user(status, ustatus))
1316 return -EFAULT;
1317 return ret;
1322 * I don't know what the parameters are: the first one
1323 * seems to be a timeval pointer, and I suspect the second
1324 * one is the time remaining.. Ho humm.. No documentation.
1326 asmlinkage int osf_usleep_thread(struct timeval32 *sleep, struct timeval32 *remain)
1328 struct timeval tmp;
1329 unsigned long ticks;
1331 if (get_tv32(&tmp, sleep))
1332 goto fault;
1334 ticks = tmp.tv_usec;
1335 ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
1336 ticks += tmp.tv_sec * HZ;
1338 current->state = TASK_INTERRUPTIBLE;
1339 ticks = schedule_timeout(ticks);
1341 if (remain) {
1342 tmp.tv_sec = ticks / HZ;
1343 tmp.tv_usec = ticks % HZ;
1344 if (put_tv32(remain, &tmp))
1345 goto fault;
1348 return 0;
1349 fault:
1350 return -EFAULT;
1354 struct timex32 {
1355 unsigned int modes; /* mode selector */
1356 long offset; /* time offset (usec) */
1357 long freq; /* frequency offset (scaled ppm) */
1358 long maxerror; /* maximum error (usec) */
1359 long esterror; /* estimated error (usec) */
1360 int status; /* clock command/status */
1361 long constant; /* pll time constant */
1362 long precision; /* clock precision (usec) (read only) */
1363 long tolerance; /* clock frequency tolerance (ppm)
1364 * (read only)
1366 struct timeval32 time; /* (read only) */
1367 long tick; /* (modified) usecs between clock ticks */
1369 long ppsfreq; /* pps frequency (scaled ppm) (ro) */
1370 long jitter; /* pps jitter (us) (ro) */
1371 int shift; /* interval duration (s) (shift) (ro) */
1372 long stabil; /* pps stability (scaled ppm) (ro) */
1373 long jitcnt; /* jitter limit exceeded (ro) */
1374 long calcnt; /* calibration intervals (ro) */
1375 long errcnt; /* calibration errors (ro) */
1376 long stbcnt; /* stability limit exceeded (ro) */
1378 int :32; int :32; int :32; int :32;
1379 int :32; int :32; int :32; int :32;
1380 int :32; int :32; int :32; int :32;
1383 asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
1385 struct timex txc;
1386 int ret;
1388 /* copy relevant bits of struct timex. */
1389 if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
1390 copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) -
1391 offsetof(struct timex32, time)))
1392 return -EFAULT;
1394 if ((ret = do_adjtimex(&txc)))
1395 return ret;
1397 /* copy back to timex32 */
1398 if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
1399 (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) -
1400 offsetof(struct timex32, tick))) ||
1401 (put_tv32(&txc_p->time, &txc.time)))
1402 return -EFAULT;
1404 return 0;