OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [alpha/] [kernel/] [osf_sys.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
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)
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;           /* only 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,
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
 * Alpha syscall convention has no problem returning negative
130
 * values:
131
 */
132
asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4,
133
                               int a5, struct pt_regs regs)
134
{
135
        extern int sys_getpriority(int, int);
136
        int prio;
137
 
138
        prio = sys_getpriority(which, who);
139
        if (prio < 0)
140
                return prio;
141
 
142
        regs.r0 = 0; /* special return: no errors */
143
        return 20 - prio;
144
}
145
 
146
 
147
/*
148
 * Heh. As documented by DEC..
149
 */
150
asmlinkage unsigned long sys_madvise(void)
151
{
152
        return 0;
153
}
154
 
155
asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5,
156
        struct pt_regs regs)
157
{
158
        (&regs)->r20 = current->euid;
159
        return current->uid;
160
}
161
 
162
asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5,
163
        struct pt_regs regs)
164
{
165
        (&regs)->r20 = current->egid;
166
        return current->gid;
167
}
168
 
169
asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5,
170
        struct pt_regs regs)
171
{
172
        (&regs)->r20 = current->p_opptr->pid;
173
        return current->pid;
174
}
175
 
176
asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
177
        unsigned long prot, unsigned long flags, unsigned long fd,
178
        unsigned long off)
179
{
180
        struct file * file = NULL;
181
 
182
        if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED))
183
                printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags);
184
        if (!(flags & MAP_ANONYMOUS)) {
185
                if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
186
                        return -EBADF;
187
        }
188
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
189
        return do_mmap(file, addr, len, prot, flags, off);
190
}
191
 
192
 
193
/*
194
 * The OSF/1 statfs structure is much larger, but this should
195
 * match the beginning, at least.
196
 */
197
struct osf_statfs {
198
        short   f_type;
199
        short   f_flags;
200
        int     f_fsize;
201
        int     f_bsize;
202
        int     f_blocks;
203
        int     f_bfree;
204
        int     f_bavail;
205
        int     f_files;
206
        int     f_ffree;
207
        __kernel_fsid_t f_fsid;
208
} * osf_stat;
209
 
210
static void linux_to_osf_statfs (struct statfs * linux_stat, struct osf_statfs * osf_stat)
211
{
212
        osf_stat->f_type   = linux_stat->f_type;
213
        osf_stat->f_flags  = 0;  /* mount flags */
214
        /* Linux doesn't provide a "fundamental filesystem block size": */
215
        osf_stat->f_fsize  = linux_stat->f_bsize;
216
        osf_stat->f_bsize  = linux_stat->f_bsize;
217
        osf_stat->f_blocks = linux_stat->f_blocks;
218
        osf_stat->f_bfree  = linux_stat->f_bfree;
219
        osf_stat->f_bavail = linux_stat->f_bavail;
220
        osf_stat->f_files  = linux_stat->f_files;
221
        osf_stat->f_ffree  = linux_stat->f_ffree;
222
        osf_stat->f_fsid   = linux_stat->f_fsid;
223
}
224
 
225
 
226
asmlinkage int osf_statfs(char * path, struct osf_statfs * buffer, unsigned long bufsiz)
227
{
228
        struct statfs linux_stat;
229
        struct inode * inode;
230
        int retval;
231
 
232
        if (bufsiz > sizeof(struct osf_statfs))
233
                bufsiz = sizeof(struct osf_statfs);
234
        retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
235
        if (retval)
236
                return retval;
237
        retval = namei(path, &inode);
238
        if (retval)
239
                return retval;
240
        if (!inode->i_sb->s_op->statfs) {
241
                iput(inode);
242
                return -ENOSYS;
243
        }
244
        inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
245
        linux_to_osf_statfs(&linux_stat, buffer);
246
        iput(inode);
247
        return 0;
248
}
249
 
250
asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs * buffer, unsigned long bufsiz)
251
{
252
        struct statfs linux_stat;
253
        struct file * file;
254
        struct inode * inode;
255
        int retval;
256
 
257
        retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
258
        if (retval)
259
                return retval;
260
        if (bufsiz > sizeof(struct osf_statfs))
261
                bufsiz = sizeof(struct osf_statfs);
262
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
263
                return -EBADF;
264
        if (!(inode = file->f_inode))
265
                return -ENOENT;
266
        if (!inode->i_sb->s_op->statfs)
267
                return -ENOSYS;
268
        inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
269
        linux_to_osf_statfs(&linux_stat, buffer);
270
        return 0;
271
}
272
 
273
/*
274
 * Uhh.. OSF/1 mount parameters aren't exactly obvious..
275
 *
276
 * Although to be frank, neither are the native Linux/i386 ones..
277
 */
278
struct ufs_args {
279
        char * devname;
280
        int flags;
281
        uid_t exroot;
282
};
283
 
284
struct cdfs_args {
285
        char * devname;
286
        int flags;
287
        uid_t exroot;
288
/*
289
 * this has lots more here, which linux handles with the option block
290
 * but I'm too lazy to do the translation into ascii..
291
 */
292
};
293
 
294
struct procfs_args {
295
        char * devname;
296
        int flags;
297
        uid_t exroot;
298
};
299
 
300
static int getdev(const char * name, int rdonly, struct inode ** ino)
301
{
302
        kdev_t dev;
303
        struct inode * inode;
304
        struct file_operations * fops;
305
        int retval;
306
 
307
        retval = namei(name, &inode);
308
        if (retval)
309
                return retval;
310
        if (!S_ISBLK(inode->i_mode)) {
311
                iput(inode);
312
                return -ENOTBLK;
313
        }
314
        if (IS_NODEV(inode)) {
315
                iput(inode);
316
                return -EACCES;
317
        }
318
        dev = inode->i_rdev;
319
        if (MAJOR(dev) >= MAX_BLKDEV) {
320
                iput(inode);
321
                return -ENXIO;
322
        }
323
        fops = get_blkfops(MAJOR(dev));
324
        if (!fops) {
325
                iput(inode);
326
                return -ENODEV;
327
        }
328
        if (fops->open) {
329
                struct file dummy;
330
                memset(&dummy, 0, sizeof(dummy));
331
                dummy.f_inode = inode;
332
                dummy.f_mode = rdonly ? 1 : 3;
333
                retval = fops->open(inode, &dummy);
334
                if (retval) {
335
                        iput(inode);
336
                        return retval;
337
                }
338
        }
339
        *ino = inode;
340
        return 0;
341
}
342
 
343
static void putdev(struct inode * inode)
344
{
345
        struct file_operations * fops;
346
 
347
        fops = get_blkfops(MAJOR(inode->i_rdev));
348
        if (fops->release)
349
                fops->release(inode, NULL);
350
}
351
 
352
/*
353
 * We can't actually handle ufs yet, so we translate UFS mounts to
354
 * ext2fs mounts... I wouldn't mind a UFS filesystem, but the UFS
355
 * layout is so braindead it's a major headache doing it..
356
 */
357
static int osf_ufs_mount(char * dirname, struct ufs_args * args, int flags)
358
{
359
        int retval;
360
        struct inode * inode;
361
        struct cdfs_args tmp;
362
 
363
        retval = verify_area(VERIFY_READ, args, sizeof(*args));
364
        if (retval)
365
                return retval;
366
        memcpy_fromfs(&tmp, args, sizeof(tmp));
367
        retval = getdev(tmp.devname, 0, &inode);
368
        if (retval)
369
                return retval;
370
        retval = do_mount(inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL);
371
        if (retval)
372
                putdev(inode);
373
        iput(inode);
374
        return retval;
375
}
376
 
377
static int osf_cdfs_mount(char * dirname, struct cdfs_args * args, int flags)
378
{
379
        int retval;
380
        struct inode * inode;
381
        struct cdfs_args tmp;
382
 
383
        retval = verify_area(VERIFY_READ, args, sizeof(*args));
384
        if (retval)
385
                return retval;
386
        memcpy_fromfs(&tmp, args, sizeof(tmp));
387
        retval = getdev(tmp.devname, 1, &inode);
388
        if (retval)
389
                return retval;
390
        retval = do_mount(inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL);
391
        if (retval)
392
                putdev(inode);
393
        iput(inode);
394
        return retval;
395
}
396
 
397
static int osf_procfs_mount(char * dirname, struct procfs_args * args, int flags)
398
{
399
        kdev_t dev;
400
        int retval;
401
        struct procfs_args tmp;
402
 
403
        retval = verify_area(VERIFY_READ, args, sizeof(*args));
404
        if (retval)
405
                return retval;
406
        memcpy_fromfs(&tmp, args, sizeof(tmp));
407
        dev = get_unnamed_dev();
408
        if (!dev)
409
                return -ENODEV;
410
        retval = do_mount(dev, "", dirname, "proc", flags, NULL);
411
        if (retval)
412
                put_unnamed_dev(dev);
413
        return retval;
414
}
415
 
416
asmlinkage int osf_mount(unsigned long typenr, char * path, int flag, void * data)
417
{
418
        int retval;
419
 
420
        retval = -EINVAL;
421
        switch (typenr) {
422
                case 1:
423
                        retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
424
                        break;
425
                case 6:
426
                        retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag);
427
                        break;
428
                case 9:
429
                        retval = osf_procfs_mount(path, (struct procfs_args *) data, flag);
430
                        break;
431
                default:
432
                        printk("osf_mount(%ld, %x)\n", typenr, flag);
433
        }
434
        return retval;
435
}
436
 
437
asmlinkage int osf_umount(char * path, int flag)
438
{
439
        return sys_umount(path);
440
}
441
 
442
/*
443
 * I don't know what the parameters are: the first one
444
 * seems to be a timeval pointer, and I suspect the second
445
 * one is the time remaining.. Ho humm.. No documentation.
446
 */
447
asmlinkage int osf_usleep_thread(struct timeval * sleep, struct timeval * remain)
448
{
449
        struct timeval tmp;
450
        unsigned long ticks;
451
        int retval;
452
 
453
        retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep));
454
        if (retval)
455
                return retval;
456
        if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain))))
457
                return retval;
458
        memcpy_fromfs(&tmp, sleep, sizeof(*sleep));
459
        ticks = tmp.tv_usec;
460
        ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
461
        ticks += tmp.tv_sec * HZ;
462
        current->timeout = ticks + jiffies;
463
        current->state = TASK_INTERRUPTIBLE;
464
        schedule();
465
        if (!remain)
466
                return 0;
467
        ticks = jiffies;
468
        if (ticks < current->timeout)
469
                ticks = current->timeout - ticks;
470
        else
471
                ticks = 0;
472
        current->timeout = 0;
473
        tmp.tv_sec = ticks / HZ;
474
        tmp.tv_usec = ticks % HZ;
475
        memcpy_tofs(remain, &tmp, sizeof(*remain));
476
        return 0;
477
}
478
 
479
asmlinkage int osf_utsname(char * name)
480
{
481
        int error = verify_area(VERIFY_WRITE, name, 5*32);
482
        if (error)
483
                return error;
484
        memcpy_tofs(name +   0, system_utsname.sysname, 32);
485
        memcpy_tofs(name +  32, system_utsname.nodename, 32);
486
        memcpy_tofs(name +  64, system_utsname.release, 32);
487
        memcpy_tofs(name +  96, system_utsname.version, 32);
488
        memcpy_tofs(name + 128, system_utsname.machine, 32);
489
        return 0;
490
}
491
 
492
asmlinkage int osf_swapon(const char * path, int flags, int lowat, int hiwat)
493
{
494
        /* for now, simply ignore lowat and hiwat... */
495
        return sys_swapon(path, flags);
496
}
497
 
498
asmlinkage unsigned long sys_getpagesize(void)
499
{
500
        return PAGE_SIZE;
501
}
502
 
503
asmlinkage unsigned long sys_getdtablesize(void)
504
{
505
        return NR_OPEN;
506
}
507
 
508
asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5,
509
        struct pt_regs regs)
510
{
511
        int fd[2];
512
        int error;
513
 
514
        error = do_pipe(fd);
515
        if (error)
516
                return error;
517
        (&regs)->r20 = fd[1];
518
        return fd[0];
519
}
520
 
521
/*
522
 * For compatibility with OSF/1 only.  Use utsname(2) instead.
523
 */
524
asmlinkage int osf_getdomainname(char *name, int namelen)
525
{
526
        unsigned len;
527
        int i, error;
528
 
529
        error = verify_area(VERIFY_WRITE, name, namelen);
530
        if (error)
531
                return error;
532
 
533
        len = namelen;
534
        if (namelen > 32)
535
          len = 32;
536
 
537
        for (i = 0; i < len; ++i) {
538
                put_user(system_utsname.domainname[i], name + i);
539
                if (system_utsname.domainname[i] == '\0')
540
                  break;
541
        }
542
        return 0;
543
}
544
 
545
 
546
asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
547
{
548
        unsigned long raddr;
549
        int err;
550
 
551
        err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
552
        if (err)
553
                return err;
554
        /*
555
         * This works because all user-level addresses are
556
         * non-negative longs!
557
         */
558
        return raddr;
559
}
560
 
561
 
562
/*
563
 * The following stuff should move into a header file should it ever
564
 * be labeled "officially supported."  Right now, there is just enough
565
 * support to avoid applications (such as tar) printing error
566
 * messages.  The attributes are not really implemented.
567
 */
568
 
569
/*
570
 * Values for Property list entry flag
571
 */
572
#define PLE_PROPAGATE_ON_COPY           0x1     /* cp(1) will copy entry
573
                                                   by default */
574
#define PLE_FLAG_MASK                   0x1     /* Valid flag values */
575
#define PLE_FLAG_ALL                    -1      /* All flag value */
576
 
577
struct proplistname_args {
578
        unsigned int    pl_mask;
579
        unsigned int    pl_numnames;
580
        char            **pl_names;
581
};
582
 
583
union pl_args {
584
        struct setargs {
585
                char *path;
586
                long follow;
587
                long nbytes;
588
                char *buf;
589
        } set;
590
        struct fsetargs {
591
                long fd;
592
                long nbytes;
593
                char *buf;
594
        } fset;
595
        struct getargs {
596
                char *path;
597
                long follow;
598
                struct proplistname_args *name_args;
599
                long nbytes;
600
                char *buf;
601
                int *min_buf_size;
602
        } get;
603
        struct fgetargs {
604
                long fd;
605
                struct proplistname_args *name_args;
606
                long nbytes;
607
                char *buf;
608
                int *min_buf_size;
609
        } fget;
610
        struct delargs {
611
                char *path;
612
                long follow;
613
                struct proplistname_args *name_args;
614
        } del;
615
        struct fdelargs {
616
                long fd;
617
                struct proplistname_args *name_args;
618
        } fdel;
619
};
620
 
621
enum pl_code {
622
        PL_SET  = 1,    PL_FSET = 2,
623
        PL_GET  = 3,    PL_FGET = 4,
624
        PL_DEL  = 5,    PL_FDEL = 6
625
};
626
 
627
asmlinkage long osf_proplist_syscall (enum pl_code code, union pl_args *args)
628
{
629
        long error;
630
        int *min_buf_size_ptr;
631
 
632
        switch (code) {
633
              case PL_SET:
634
                error = verify_area(VERIFY_READ, &args->set.nbytes,
635
                                    sizeof(args->set.nbytes));
636
                if (error)
637
                  return error;
638
                return args->set.nbytes;
639
 
640
              case PL_FSET:
641
                error = verify_area(VERIFY_READ, &args->fset.nbytes,
642
                                    sizeof(args->fset.nbytes));
643
                if (error)
644
                  return error;
645
                return args->fset.nbytes;
646
 
647
              case PL_GET:
648
                error = verify_area(VERIFY_READ, &args->get.min_buf_size,
649
                                    sizeof(args->get.min_buf_size));
650
                if (error)
651
                  return error;
652
                min_buf_size_ptr = get_user(&args->get.min_buf_size);
653
                error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
654
                                    sizeof(*min_buf_size_ptr));
655
                if (error)
656
                  return error;
657
                put_user(0, min_buf_size_ptr);
658
                return 0;
659
 
660
              case PL_FGET:
661
                error = verify_area(VERIFY_READ, &args->fget.min_buf_size,
662
                                    sizeof(args->fget.min_buf_size));
663
                if (error)
664
                  return error;
665
                min_buf_size_ptr = get_user(&args->fget.min_buf_size);
666
                error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
667
                                    sizeof(*min_buf_size_ptr));
668
                if (error)
669
                  return error;
670
                put_user(0, min_buf_size_ptr);
671
                return 0;
672
 
673
              case PL_DEL:
674
              case PL_FDEL:
675
                return 0;
676
 
677
              default:
678
                return -EOPNOTSUPP;
679
        }
680
}
681
 
682
/*
683
 * The Linux kernel isn't good at returning values that look
684
 * like negative longs (they are mistaken as error values).
685
 * Until that is fixed, we need this little workaround for
686
 * create_module() because it's one of the few system calls
687
 * that return kernel addresses (which are negative).
688
 */
689
asmlinkage unsigned long
690
alpha_create_module (char * module_name, unsigned long size,
691
                     int a3, int a4, int a5, int a6,
692
                     struct pt_regs regs)
693
{
694
        asmlinkage unsigned long sys_create_module (char *, unsigned long);
695
        long retval;
696
 
697
        retval = sys_create_module(module_name, size);
698
        /*
699
         * we get either a module address or an error number,
700
         * and we know the error number is a small negative
701
         * number, while the address is always negative but
702
         * much larger.
703
         */
704
        if (retval + 1000 > 0)
705
          return retval;
706
 
707
        /* tell entry.S:syscall_error that this is NOT an error: */
708
        regs.r0 = 0;
709
        return retval;
710
}
711
 
712
 
713
asmlinkage unsigned long
714
osf_getsysinfo (unsigned long op, void * buffer, unsigned long nbytes,
715
                int * start, void *arg)
716
{
717
        switch (op) {
718
        case 45:        /* GSI_IEEE_FP_CONTROL */
719
                /* Return current sw control & status bits.  */
720
                put_user(current->tss.flags & IEEE_SW_MASK,
721
                         (unsigned long *)buffer);
722
                return 0;
723
 
724
        case 46:        /* GSI_IEEE_STATE_AT_SIGNAL */
725
                /*
726
                 * Not sure anybody will ever use this weird stuff.  These
727
                 * ops can be used (under OSF/1) to set the fpcr that should
728
                 * be used when a signal handler starts executing.
729
                 */
730
                break;
731
 
732
        default:
733
                break;
734
        }
735
        return -EOPNOTSUPP;
736
}
737
 
738
 
739
asmlinkage unsigned long
740
osf_setsysinfo (unsigned long op, void * buffer, unsigned long nbytes,
741
                int * start, void *arg)
742
{
743
        switch (op) {
744
        case 14: {      /* SSI_IEEE_FP_CONTROL */
745
                unsigned long sw, fpcw;
746
 
747
                /*
748
                 * Alpha Architecture Handbook 4.7.7.3:
749
                 * To be fully IEEE compiant, we must track the current IEEE
750
                 * exception state in software, because spurrious bits can be
751
                 * set in the trap shadow of a software-complete insn.
752
                 */
753
 
754
                /* Update software trap enable bits.  */
755
                sw = get_user((unsigned long *) buffer) & IEEE_SW_MASK;
756
                current->tss.flags &= ~IEEE_SW_MASK;
757
                current->tss.flags |= sw & IEEE_SW_MASK;
758
 
759
                /* Update the real fpcr.  For exceptions that are disabled,
760
                   but that we have seen, turn off exceptions in h/w.
761
                   Otherwise leave them enabled so that we can update our
762
                   software status mask.  */
763
                fpcw = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
764
                fpcw |= ieee_sw_to_fpcr(sw | ((~sw & IEEE_STATUS_MASK) >> 16));
765
                wrfpcr(fpcw);
766
                return 0;
767
        }
768
 
769
        case 15:        /* SSI_IEEE_STATE_AT_SIGNAL */
770
        case 16:        /* SSI_IEEE_IGNORE_STATE_AT_SIGNAL */
771
                /*
772
                 * Not sure anybody will ever use this weird stuff.  These
773
                 * ops can be used (under OSF/1) to set the fpcr that should
774
                 * be used when a signal handler starts executing.
775
                 */
776
                break;
777
 
778
        default:
779
                break;
780
        }
781
        return -EOPNOTSUPP;
782
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.