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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [sparc/] [kernel/] [sys_sunos.c] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/* $Id: sys_sunos.c,v 1.1.1.1 2001-09-10 07:44:02 simons Exp $
2
 * sys_sunos.c: SunOS specific syscall compatibility support.
3
 *
4
 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5
 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
6
 *
7
 * Based upon preliminary work which is:
8
 *
9
 * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
10
 *
11
 * The sunos_poll routine is based on iBCS2's poll routine, this
12
 * is the copyright message for that file:
13
 *
14
 * This file contains the procedures for the handling of poll.
15
 *
16
 * Copyright (C) 1994 Eric Youngdale
17
 *
18
 * Created for Linux based loosely upon linux select code, which
19
 * in turn is loosely based upon Mathius Lattner's minix
20
 * patches by Peter MacDonald. Heavily edited by Linus.
21
 *
22
 * Poll is used by SVr4 instead of select, and it has considerably
23
 * more functionality.  Parts of it are related to STREAMS, and since
24
 * we do not have streams, we fake it.  In fact, select() still exists
25
 * under SVr4, but libc turns it into a poll() call instead.  We attempt
26
 * to do the inverse mapping.
27
 */
28
 
29
#include <linux/kernel.h>
30
#include <linux/sched.h>
31
#include <linux/types.h>
32
#include <linux/mman.h>
33
#include <linux/mm.h>
34
#include <linux/swap.h>
35
#include <linux/fs.h>
36
#include <linux/resource.h>
37
#include <linux/ipc.h>
38
#include <linux/shm.h>
39
#include <linux/signal.h>
40
#include <linux/uio.h>
41
#include <linux/utsname.h>
42
#include <linux/fs.h>
43
#include <linux/major.h>
44
#include <linux/stat.h>
45
#include <linux/malloc.h>
46
#include <linux/pagemap.h>
47
 
48
#include <asm/segment.h>
49
#ifndef KERNEL_DS
50
#include <linux/segment.h>
51
#endif
52
 
53
#include <asm/page.h>
54
#include <asm/pgtable.h>
55
#include <asm/pconf.h>
56
#include <asm/idprom.h> /* for gethostid() */
57
#include <asm/unistd.h>
58
#include <asm/system.h>
59
 
60
/* For the nfs mount emulation */
61
#include <linux/socket.h>
62
#include <linux/in.h>
63
#include <linux/nfs.h>
64
#include <linux/nfs_mount.h>
65
 
66
/* for sunos_select */
67
#include <linux/time.h>
68
#include <linux/personality.h>
69
 
70
extern unsigned long get_sparc_unmapped_area(unsigned long len);
71
 
72
/* We use the SunOS mmap() semantics. */
73
asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
74
                                    unsigned long prot, unsigned long flags,
75
                                    unsigned long fd, unsigned long off)
76
{
77
        struct file * file = NULL;
78
        unsigned long retval, ret_type;
79
 
80
        if(flags & MAP_NORESERVE) {
81
                printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n",
82
                       current->comm);
83
                flags &= ~MAP_NORESERVE;
84
        }
85
        if(!(flags & MAP_ANONYMOUS))
86
                if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
87
                        return -EBADF;
88
        if(!(flags & MAP_FIXED) && !addr) {
89
                addr = get_sparc_unmapped_area(len);
90
                if(!addr)
91
                        return -ENOMEM;
92
        }
93
        /* If this is ld.so or a shared library doing an mmap
94
         * of /dev/zero, transform it into an anonymous mapping.
95
         * SunOS is so stupid some times... hmph!
96
         */
97
        if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR &&
98
           MINOR(file->f_inode->i_rdev) == 5) {
99
                flags |= MAP_ANONYMOUS;
100
                file = 0;
101
        }
102
        ret_type = flags & _MAP_NEW;
103
        flags &= ~_MAP_NEW;
104
        retval = do_mmap(file, addr, len, prot, flags, off);
105
        if(ret_type)
106
                return retval;
107
        else
108
                return ((retval < KERNBASE) ? 0 : retval);
109
}
110
 
111
/* lmbench calls this, just say "yeah, ok" */
112
asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, char *arg)
113
{
114
        return 0;
115
}
116
 
117
/* SunOS is completely broken... it returns 0 on success, otherwise
118
 * ENOMEM.  For sys_sbrk() it wants the new brk value as a return
119
 * on success and ENOMEM as before on failure.
120
 */
121
asmlinkage int sunos_brk(unsigned long brk)
122
{
123
        int freepages;
124
        unsigned long rlim;
125
        unsigned long newbrk, oldbrk;
126
 
127
        if (brk < current->mm->end_code)
128
                return -ENOMEM;
129
 
130
        newbrk = PAGE_ALIGN(brk);
131
        oldbrk = PAGE_ALIGN(current->mm->brk);
132
        if (oldbrk == newbrk) {
133
                current->mm->brk = brk;
134
                return 0;
135
        }
136
 
137
        /*
138
         * Always allow shrinking brk
139
         */
140
        if (brk <= current->mm->brk) {
141
                current->mm->brk = brk;
142
                do_munmap(newbrk, oldbrk-newbrk);
143
                return 0;
144
        }
145
        /*
146
         * Check against rlimit and stack..
147
         */
148
        rlim = current->rlim[RLIMIT_DATA].rlim_cur;
149
        if (rlim >= RLIM_INFINITY)
150
                rlim = ~0;
151
        if (brk - current->mm->end_code > rlim)
152
                return -ENOMEM;
153
 
154
        /*
155
         * Check against existing mmap mappings.
156
         */
157
        if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
158
                return -ENOMEM;
159
 
160
        /*
161
         * stupid algorithm to decide if we have enough memory: while
162
         * simple, it hopefully works in most obvious cases.. Easy to
163
         * fool it, but this should catch most mistakes.
164
         */
165
        freepages = buffermem >> PAGE_SHIFT;
166
        freepages += page_cache_size;
167
        freepages >>= 1;
168
        freepages += nr_free_pages;
169
        freepages += nr_swap_pages;
170
        freepages -= MAP_NR(high_memory) >> 4;
171
        freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
172
        if (freepages < 0)
173
                return -ENOMEM;
174
        /*
175
         * Ok, we have probably got enough memory - let it rip.
176
         */
177
        current->mm->brk = brk;
178
        do_mmap(NULL, oldbrk, newbrk-oldbrk,
179
                PROT_READ|PROT_WRITE|PROT_EXEC,
180
                MAP_FIXED|MAP_PRIVATE, 0);
181
        return 0;
182
}
183
 
184
asmlinkage unsigned long sunos_sbrk(int increment)
185
{
186
        int error;
187
 
188
        /* This should do it hopefully... */
189
        error = sunos_brk(((int) current->mm->brk) + increment);
190
        if(error)
191
                return error;
192
        else
193
                return current->mm->brk;
194
}
195
 
196
/* XXX Completely undocumented, and completely magic...
197
 * XXX I believe it is to increase the size of the stack by
198
 * XXX argument 'increment' and return the new end of stack
199
 * XXX area.  Wheee...
200
 */
201
asmlinkage unsigned long sunos_sstk(int increment)
202
{
203
        printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n",
204
               current->comm, increment);
205
        return -1;
206
}
207
 
208
/* Give hints to the kernel as to what paging strategy to use...
209
 * Completely bogus, don't remind me.
210
 */
211
#define VA_NORMAL     0 /* Normal vm usage expected */
212
#define VA_ABNORMAL   1 /* Abnormal/random vm usage probable */
213
#define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */
214
#define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */
215
static char *vstrings[] = {
216
        "VA_NORMAL",
217
        "VA_ABNORMAL",
218
        "VA_SEQUENTIAL",
219
        "VA_INVALIDATE",
220
};
221
 
222
asmlinkage void sunos_vadvise(unsigned long strategy)
223
{
224
        /* I wanna see who uses this... */
225
        printk("%s: Advises us to use %s paging strategy\n",
226
               current->comm,
227
               strategy <= 3 ? vstrings[strategy] : "BOGUS");
228
        return; /* We don't do diddly... */
229
}
230
 
231
/* Same as vadvise, and just as bogus, but for a range of virtual
232
 * process address space.
233
 */
234
#define MADV_NORMAL      0 /* Nothing special... */
235
#define MADV_RANDOM      1 /* I am emacs... */
236
#define MADV_SEQUENTIAL  2 /* I am researcher code... */
237
#define MADV_WILLNEED    3 /* Pages in this range will be needed */
238
#define MADV_DONTNEED    4 /* Pages in this range won't be needed */
239
 
240
static char *mstrings[] = {
241
        "MADV_NORMAL",
242
        "MADV_RANDOM",
243
        "MADV_SEQUENTIAL",
244
        "MADV_WILLNEED",
245
        "MADV_DONTNEED",
246
};
247
 
248
asmlinkage void sunos_madvise(unsigned long address, unsigned long len,
249
                              unsigned long strategy)
250
{
251
        /* I wanna see who uses this... */
252
        printk("%s: Advises us to use %s paging strategy for addr<%08lx> len<%08lx>\n",
253
               current->comm,
254
               strategy <= 4 ? mstrings[strategy] : "BOGUS",
255
               address, len);
256
        return; /* We don't do diddly... */
257
}
258
 
259
/* Places into character array, the status of all the pages in the passed
260
 * range from 'addr' to 'addr + len'.  -1 on failure, 0 on success...
261
 * The encoding in each character is:
262
 * low-bit is zero == Page is not in physical ram right now
263
 * low-bit is one  == Page is currently residing in core
264
 * All other bits are undefined within the character so there...
265
 * Also, if you try to get stats on an area outside of the user vm area
266
 * *or* the passed base address is not aligned on a page boundary you
267
 * get an error.
268
 */
269
asmlinkage int sunos_mincore(unsigned long addr, unsigned long len, char *array)
270
{
271
        pgd_t *pgdp;
272
        pmd_t *pmdp;
273
        pte_t *ptep;
274
        unsigned long limit;
275
        int num_pages, pnum;
276
 
277
        if(addr & (PAGE_SIZE - 1))
278
                return -EINVAL;
279
 
280
        num_pages = (len / PAGE_SIZE);
281
        if(verify_area(VERIFY_WRITE, array, num_pages))
282
                return -EFAULT; /* bum array, you lose... */
283
        if((addr >= KERNBASE) || ((addr + len) > KERNBASE))
284
                return -ENOMEM; /* I'm sure you're curious about kernel mappings.. */
285
 
286
        /* Wheee, go through pte's */
287
        pnum = 0;
288
        for(limit = addr + len; addr < limit; addr += PAGE_SIZE, pnum++) {
289
                pgdp = pgd_offset(current->mm, addr);
290
                if(pgd_none(*pgdp))
291
                        return -ENOMEM; /* As per SunOS manpage */
292
                pmdp = pmd_offset(pgdp, addr);
293
                if(pmd_none(*pmdp))
294
                        return -ENOMEM; /* As per SunOS manpage */
295
                ptep = pte_offset(pmdp, addr);
296
                if(pte_none(*ptep))
297
                        return -ENOMEM; /* As per SunOS manpage */
298
                /* Page in core or Swapped page? */
299
                array[pnum] = pte_present(*ptep) ? 1 : 0;
300
        }
301
        return 0; /* Success... I think... */
302
}
303
 
304
/* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE
305
 * resource limit and is for backwards compatibility with older sunos
306
 * revs.
307
 */
308
asmlinkage long sunos_getdtablesize(void)
309
{
310
        return NR_OPEN;
311
}
312
#define _S(nr) (1<<((nr)-1))
313
 
314
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
315
 
316
asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask)
317
{
318
        unsigned long flags;
319
        unsigned long old;
320
 
321
        save_flags(flags); cli();
322
        old = current->blocked;
323
        current->blocked |= (blk_mask & _BLOCKABLE);
324
        restore_flags(flags);
325
        return old;
326
}
327
 
328
asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask)
329
{
330
        unsigned long flags;
331
        unsigned long retval;
332
 
333
        save_flags(flags); cli();
334
        retval = current->blocked;
335
        current->blocked = newmask & _BLOCKABLE;
336
        restore_flags(flags);
337
        return retval;
338
}
339
 
340
/* SunOS getdents is very similar to the newer Linux (iBCS2 compliant)    */
341
/* getdents system call, the format of the structure just has a different */
342
/* layout (d_off+d_ino instead of d_ino+d_off) */
343
struct sunos_dirent {
344
    long           d_off;
345
    unsigned long  d_ino;
346
    unsigned short d_reclen;
347
    unsigned short d_namlen;
348
    char           d_name[1];
349
};
350
 
351
struct sunos_dirent_callback {
352
    struct sunos_dirent *curr;
353
    struct sunos_dirent *previous;
354
    int count;
355
    int error;
356
};
357
 
358
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
359
#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
360
 
361
static int sunos_filldir(void * __buf, const char * name, int namlen,
362
                         off_t offset, ino_t ino)
363
{
364
        struct sunos_dirent * dirent;
365
        struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
366
        int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
367
 
368
        buf->error = -EINVAL;   /* only used if we fail.. */
369
        if (reclen > buf->count)
370
                return -EINVAL;
371
        dirent = buf->previous;
372
        if (dirent)
373
                put_user(offset, &dirent->d_off);
374
        dirent = buf->curr;
375
        buf->previous = dirent;
376
        put_user(ino, &dirent->d_ino);
377
        put_user(namlen, &dirent->d_namlen);
378
        put_user(reclen, &dirent->d_reclen);
379
        memcpy_tofs(dirent->d_name, name, namlen);
380
        put_user(0, dirent->d_name + namlen);
381
        ((char *) dirent) += reclen;
382
        buf->curr = dirent;
383
        buf->count -= reclen;
384
        return 0;
385
}
386
 
387
asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
388
{
389
        struct file * file;
390
        struct sunos_dirent * lastdirent;
391
        struct sunos_dirent_callback buf;
392
        int error;
393
 
394
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
395
                return -EBADF;
396
        if (!file->f_op || !file->f_op->readdir)
397
                return -ENOTDIR;
398
        if(verify_area(VERIFY_WRITE, dirent, cnt))
399
                return -EFAULT;
400
        if(cnt < (sizeof(struct sunos_dirent) + 255))
401
                return -EINVAL;
402
 
403
        buf.curr = (struct sunos_dirent *) dirent;
404
        buf.previous = NULL;
405
        buf.count = cnt;
406
        buf.error = 0;
407
        error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir);
408
        if (error < 0)
409
                return error;
410
        lastdirent = buf.previous;
411
        if (!lastdirent)
412
                return buf.error;
413
        put_user(file->f_pos, &lastdirent->d_off);
414
        return cnt - buf.count;
415
}
416
 
417
/* Old sunos getdirentries, severely broken compatibility stuff here. */
418
struct sunos_direntry {
419
    unsigned long  d_ino;
420
    unsigned short d_reclen;
421
    unsigned short d_namlen;
422
    char           d_name[1];
423
};
424
 
425
struct sunos_direntry_callback {
426
    struct sunos_direntry *curr;
427
    struct sunos_direntry *previous;
428
    int count;
429
    int error;
430
};
431
 
432
static int sunos_filldirentry(void * __buf, const char * name, int namlen,
433
                              off_t offset, ino_t ino)
434
{
435
        struct sunos_direntry * dirent;
436
        struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf;
437
        int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
438
 
439
        buf->error = -EINVAL;   /* only used if we fail.. */
440
        if (reclen > buf->count)
441
                return -EINVAL;
442
        dirent = buf->previous;
443
        dirent = buf->curr;
444
        buf->previous = dirent;
445
        put_user(ino, &dirent->d_ino);
446
        put_user(namlen, &dirent->d_namlen);
447
        put_user(reclen, &dirent->d_reclen);
448
        memcpy_tofs(dirent->d_name, name, namlen);
449
        put_user(0, dirent->d_name + namlen);
450
        ((char *) dirent) += reclen;
451
        buf->curr = dirent;
452
        buf->count -= reclen;
453
        return 0;
454
}
455
 
456
asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
457
{
458
        struct file * file;
459
        struct sunos_direntry * lastdirent;
460
        struct sunos_direntry_callback buf;
461
        int error;
462
 
463
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
464
                return -EBADF;
465
        if (!file->f_op || !file->f_op->readdir)
466
                return -ENOTDIR;
467
        if(verify_area(VERIFY_WRITE, dirent, cnt) ||
468
           verify_area(VERIFY_WRITE, basep, sizeof(unsigned int)))
469
                return -EFAULT;
470
        if(cnt < (sizeof(struct sunos_direntry) + 255))
471
                return -EINVAL;
472
 
473
        buf.curr = (struct sunos_direntry *) dirent;
474
        buf.previous = NULL;
475
        buf.count = cnt;
476
        buf.error = 0;
477
        error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
478
        if (error < 0)
479
                return error;
480
        lastdirent = buf.previous;
481
        if (!lastdirent)
482
                return buf.error;
483
        put_user(file->f_pos, basep);
484
        return cnt - buf.count;
485
}
486
 
487
asmlinkage int sunos_getdomainname(char *name, int len)
488
{
489
        int error;
490
 
491
        if(len > __NEW_UTS_LEN)
492
                return -EFAULT;
493
        error = verify_area(VERIFY_WRITE, name, len);
494
        if(error)
495
                return -EFAULT;
496
        memcpy_tofs(name, system_utsname.domainname, len);
497
        return 0;
498
}
499
 
500
struct sunos_utsname {
501
        char sname[9];
502
        char nname[9];
503
        char nnext[56];
504
        char rel[9];
505
        char ver[9];
506
        char mach[9];
507
};
508
 
509
asmlinkage int sunos_uname(struct sunos_utsname *name)
510
{
511
        int error;
512
        if(!name)
513
                return -EFAULT;
514
        error = verify_area(VERIFY_WRITE, name, sizeof *name);
515
        if(error)
516
                return error;
517
        memcpy_tofs(&name->sname[0], &system_utsname.sysname[0],
518
                    sizeof(name->sname) - 1);
519
        memcpy_tofs(&name->nname[0], &system_utsname.nodename[0],
520
                    sizeof(name->nname) - 1);
521
        name->nname[8] = '\0';
522
        memcpy_tofs(&name->rel[0], &system_utsname.release[0],
523
                    sizeof(name->rel) - 1);
524
        memcpy_tofs(&name->ver[0], &system_utsname.version[0],
525
                    sizeof(name->ver) - 1);
526
        memcpy_tofs(&name->mach[0], &system_utsname.machine[0],
527
                    sizeof(name->mach) - 1);
528
        return 0;
529
}
530
 
531
asmlinkage int sunos_nosys(void)
532
{
533
        struct pt_regs *regs;
534
 
535
        regs = (struct pt_regs *) (current->saved_kernel_stack +
536
                                   sizeof(struct reg_window));
537
        current->tss.sig_address = regs->pc;
538
        current->tss.sig_desc = regs->u_regs[UREG_G1];
539
        send_sig(SIGSYS, current, 1);
540
        printk("Process makes ni_syscall number %d, register dump:\n",
541
               (int) regs->u_regs[UREG_G1]);
542
        show_regs(regs);
543
        return -ENOSYS;
544
}
545
 
546
/* This is not a real and complete implementation yet, just to keep
547
 * the easy SunOS binaries happy.
548
 */
549
asmlinkage int sunos_fpathconf(int fd, int name)
550
{
551
        switch(name) {
552
        case _PCONF_LINK:
553
                return LINK_MAX;
554
        case _PCONF_CANON:
555
                return MAX_CANON;
556
        case _PCONF_INPUT:
557
                return MAX_INPUT;
558
        case _PCONF_NAME:
559
                return NAME_MAX;
560
        case _PCONF_PATH:
561
                return PATH_MAX;
562
        case _PCONF_PIPE:
563
                return PIPE_BUF;
564
        case _PCONF_CHRESTRICT:
565
                return 1; /* XXX Investigate XXX */
566
        case _PCONF_NOTRUNC:
567
                return 0; /* XXX Investigate XXX */
568
        case _PCONF_VDISABLE:
569
                return 0;
570
        default:
571
                return -EINVAL;
572
        }
573
}
574
 
575
asmlinkage int sunos_pathconf(char *path, int name)
576
{
577
        return sunos_fpathconf(0, name); /* XXX cheese XXX */
578
}
579
 
580
/* SunOS mount system call emulation */
581
extern asmlinkage int
582
sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
583
 
584
asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
585
{
586
        /* SunOS binaries expect that select won't change the tvp contents */
587
        current->personality |= STICKY_TIMEOUTS;
588
        return sys_select (width, inp, outp, exp, tvp);
589
}
590
 
591
asmlinkage void sunos_nop(void)
592
{
593
        return;
594
}
595
 
596
/* SunOS mount/umount. */
597
#define SMNT_RDONLY       1
598
#define SMNT_NOSUID       2
599
#define SMNT_NEWTYPE      4
600
#define SMNT_GRPID        8
601
#define SMNT_REMOUNT      16
602
#define SMNT_NOSUB        32
603
#define SMNT_MULTI        64
604
#define SMNT_SYS5         128
605
 
606
struct sunos_fh_t {
607
        char fh_data [NFS_FHSIZE];
608
};
609
 
610
struct sunos_nfs_mount_args {
611
        struct sockaddr_in  *addr; /* file server address */
612
        struct nfs_fh *fh;     /* File handle to be mounted */
613
        int        flags;      /* flags */
614
        int        wsize;      /* write size in bytes */
615
        int        rsize;      /* read size in bytes */
616
        int        timeo;      /* initial timeout in .1 secs */
617
        int        retrans;    /* times to retry send */
618
        char       *hostname;  /* server's hostname */
619
        int        acregmin;   /* attr cache file min secs */
620
        int        acregmax;   /* attr cache file max secs */
621
        int        acdirmin;   /* attr cache dir min secs */
622
        int        acdirmax;   /* attr cache dir max secs */
623
        char       *netname;   /* server's netname */
624
};
625
 
626
 
627
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
628
extern dev_t get_unnamed_dev(void);
629
extern void put_unnamed_dev(dev_t);
630
extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
631
extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
632
extern asmlinkage int sys_socket(int family, int type, int protocol);
633
extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
634
 
635
 
636
/* Bind the socket on a local reserved port and connect it to the
637
 * remote server.  This on Linux/i386 is done by the mount program,
638
 * not by the kernel.
639
 */
640
static int
641
sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
642
{
643
        struct sockaddr_in local;
644
        struct sockaddr_in server;
645
        int    try_port;
646
        int    ret;
647
        struct socket *socket;
648
        struct inode  *inode;
649
        struct file   *file;
650
 
651
        file = current->files->fd [fd];
652
        inode = file->f_inode;
653
        if (!inode || !inode->i_sock)
654
                return 0;
655
 
656
        socket = &inode->u.socket_i;
657
        local.sin_family = AF_INET;
658
        local.sin_addr.s_addr = INADDR_ANY;
659
 
660
        /* IPPORT_RESERVED = 1024, can't find the definition in the kernel */
661
        try_port = 1024;
662
        do {
663
                local.sin_port = htons (--try_port);
664
                ret = socket->ops->bind(socket, (struct sockaddr*)&local,
665
                                        sizeof(local));
666
        } while (ret && try_port > (1024 / 2));
667
 
668
        if (ret)
669
                return 0;
670
 
671
        server.sin_family = AF_INET;
672
        server.sin_addr = addr->sin_addr;
673
        server.sin_port = NFS_PORT;
674
 
675
        /* Call sys_connect */
676
        ret = socket->ops->connect (socket, (struct sockaddr *) &server,
677
                                    sizeof (server), file->f_flags);
678
        if (ret < 0)
679
                return 0;
680
        return 1;
681
}
682
 
683
static int get_default (int value, int def_value)
684
{
685
    if (value)
686
        return value;
687
    else
688
        return def_value;
689
}
690
 
691
asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
692
{
693
        int  ret = -ENODEV, error;
694
        int  server_fd;
695
        char *the_name;
696
        struct nfs_mount_data linux_nfs_mount;
697
        struct sunos_nfs_mount_args *sunos_mount = data;
698
        dev_t dev;
699
 
700
        error = verify_area(VERIFY_READ, data, sizeof (struct sunos_nfs_mount_args));
701
        if (error)
702
                return error;
703
        /* Ok, here comes the fun part: Linux's nfs mount needs a
704
         * socket connection to the server, but SunOS mount does not
705
         * require this, so we use the information on the destination
706
         * address to create a socket and bind it to a reserved
707
         * port on this system
708
         */
709
        server_fd = sys_socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
710
        if (server_fd < 0)
711
                return -ENXIO;
712
 
713
        if (!sunos_nfs_get_server_fd (server_fd, sunos_mount->addr)){
714
                sys_close (server_fd);
715
                return -ENXIO;
716
        }
717
 
718
        /* Now, bind it to a locally reserved port */
719
        linux_nfs_mount.version  = NFS_MOUNT_VERSION;
720
        linux_nfs_mount.flags    = sunos_mount->flags;
721
        linux_nfs_mount.addr     = *sunos_mount->addr;
722
        linux_nfs_mount.root     = *sunos_mount->fh;
723
        linux_nfs_mount.fd       = server_fd;
724
 
725
        linux_nfs_mount.rsize    = get_default (sunos_mount->rsize, 8192);
726
        linux_nfs_mount.wsize    = get_default (sunos_mount->wsize, 8192);
727
        linux_nfs_mount.timeo    = get_default (sunos_mount->timeo, 10);
728
        linux_nfs_mount.retrans  = sunos_mount->retrans;
729
 
730
        linux_nfs_mount.acregmin = sunos_mount->acregmin;
731
        linux_nfs_mount.acregmax = sunos_mount->acregmax;
732
        linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
733
        linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
734
 
735
        if (getname (sunos_mount->hostname, &the_name))
736
                return -EFAULT;
737
 
738
        strncpy (linux_nfs_mount.hostname, the_name, 254);
739
        linux_nfs_mount.hostname [255] = 0;
740
        putname (the_name);
741
 
742
        dev = get_unnamed_dev ();
743
 
744
        ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
745
        if (ret)
746
            put_unnamed_dev(dev);
747
 
748
        return ret;
749
}
750
 
751
asmlinkage int
752
sunos_mount(char *type, char *dir, int flags, void *data)
753
{
754
        int linux_flags = MS_MGC_MSK; /* new semantics */
755
        int error;
756
        char *dev_fname = 0;
757
 
758
        /* We don't handle the integer fs type */
759
        if ((flags & SMNT_NEWTYPE) == 0)
760
                return -EINVAL;
761
 
762
        /* Do not allow for those flags we don't support */
763
        if (flags & (SMNT_GRPID|SMNT_NOSUB|SMNT_MULTI|SMNT_SYS5))
764
                return -EINVAL;
765
 
766
        if(flags & SMNT_REMOUNT)
767
                linux_flags |= MS_REMOUNT;
768
        if(flags & SMNT_RDONLY)
769
                linux_flags |= MS_RDONLY;
770
        if(flags & SMNT_NOSUID)
771
                linux_flags |= MS_NOSUID;
772
        error = verify_area(VERIFY_READ, type, 16);
773
        if(error)
774
                return error;
775
        if(strcmp(type, "ext2") == 0) {
776
                dev_fname = (char *) data;
777
        } else if(strcmp(type, "iso9660") == 0) {
778
                dev_fname = (char *) data;
779
        } else if(strcmp(type, "minix") == 0) {
780
                dev_fname = (char *) data;
781
        } else if(strcmp(type, "ext") == 0) {
782
                dev_fname = (char *) data;
783
        } else if(strcmp(type, "xiafs") == 0) {
784
                dev_fname = (char *) data;
785
        } else if(strcmp(type, "nfs") == 0) {
786
                error = sunos_nfs_mount (dir, flags, data);
787
                return error;
788
        } else if(strcmp(type, "ufs") == 0) {
789
                printk("Warning: UFS filesystem mounts unsupported.\n");
790
                return -ENODEV;
791
        } else if(strcmp(type, "proc")) {
792
                return -ENODEV;
793
        }
794
        if(error)
795
                return error;
796
        error = sys_mount(dev_fname, dir, type, linux_flags, NULL);
797
        return error;
798
}
799
 
800
extern asmlinkage int sys_setsid(void);
801
extern asmlinkage int sys_setpgid(pid_t, pid_t);
802
 
803
asmlinkage int sunos_setpgrp(pid_t pid, pid_t pgid)
804
{
805
        /* So stupid... */
806
        if((!pid || pid == current->pid) &&
807
           !pgid) {
808
                sys_setsid();
809
                return 0;
810
        } else {
811
                return sys_setpgid(pid, pgid);
812
        }
813
}
814
 
815
/* So stupid... */
816
extern asmlinkage int sys_wait4(pid_t, unsigned int *, int, struct rusage *);
817
asmlinkage int sunos_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru)
818
{
819
        return sys_wait4((pid ? pid : -1), stat_addr, options, ru);
820
}
821
 
822
extern int kill_pg(int, int, int);
823
asmlinkage int sunos_killpg(int pgrp, int sig)
824
{
825
        return kill_pg(pgrp, sig, 0);
826
}
827
 
828
asmlinkage int sunos_audit(void)
829
{
830
        printk ("sys_audit\n");
831
        return -1;
832
}
833
 
834
extern asmlinkage unsigned long sunos_gethostid(void)
835
{
836
        return (unsigned long) idprom->id_sernum;
837
}
838
 
839
extern asmlinkage long sunos_sysconf (int name)
840
{
841
        switch (name){
842
        case _SC_ARG_MAX:
843
                return ARG_MAX;
844
        case _SC_CHILD_MAX:
845
                return CHILD_MAX;
846
        case _SC_CLK_TCK:
847
                return HZ;
848
        case _SC_NGROUPS_MAX:
849
                return NGROUPS_MAX;
850
        case _SC_OPEN_MAX:
851
                return OPEN_MAX;
852
        case _SC_JOB_CONTROL:
853
                return 1;       /* yes, we do support job control */
854
        case _SC_SAVED_IDS:
855
                return 1;       /* yes, we do support saved uids  */
856
        case _SC_VERSION:
857
                /* mhm, POSIX_VERSION is in /usr/include/unistd.h
858
                 * should it go on /usr/include/linux?
859
                 */
860
                return  199009L;
861
        }
862
        return -1;
863
}
864
 
865
#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y))
866
 
867
#define POLLIN 1
868
#define POLLPRI 2
869
#define POLLOUT 4
870
#define POLLERR 8
871
#define POLLHUP 16
872
#define POLLNVAL 32
873
#define POLLRDNORM 64
874
#define POLLWRNORM POLLOUT
875
#define POLLRDBAND 128
876
#define POLLWRBAND 256
877
 
878
#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN)
879
#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT)
880
#define LINUX_POLLERR (POLLERR)
881
 
882
static inline void free_wait(select_table * p)
883
{
884
        struct select_table_entry * entry = p->entry + p->nr;
885
 
886
        while (p->nr > 0) {
887
                p->nr--;
888
                entry--;
889
                remove_wait_queue(entry->wait_address,&entry->wait);
890
        }
891
}
892
 
893
 
894
/* Copied directly from fs/select.c */
895
static int check(int flag, select_table * wait, struct file * file)
896
{
897
        struct inode * inode;
898
        struct file_operations *fops;
899
        int (*select) (struct inode *, struct file *, int, select_table *);
900
 
901
        inode = file->f_inode;
902
        if ((fops = file->f_op) && (select = fops->select))
903
                return select(inode, file, flag, wait)
904
                    || (wait && select(inode, file, flag, NULL));
905
        if (S_ISREG(inode->i_mode))
906
                return 1;
907
        return 0;
908
}
909
 
910
struct poll {
911
        int fd;
912
        short events;
913
        short revents;
914
};
915
 
916
int sunos_poll(struct poll * ufds, size_t nfds, int timeout)
917
{
918
        int i,j, count, fdcount, error, retflag;
919
        struct poll * fdpnt;
920
        struct poll * fds, *fds1;
921
        select_table wait_table, *wait;
922
        struct select_table_entry *entry;
923
 
924
        if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll))))
925
                return error;
926
 
927
        if (nfds > NR_OPEN)
928
                return -EINVAL;
929
 
930
        if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL))
931
        || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL)))
932
                return -ENOMEM;
933
 
934
        memcpy_fromfs(fds, ufds, nfds*sizeof(struct poll));
935
 
936
        if (timeout < 0)
937
                current->timeout = 0x7fffffff;
938
        else {
939
                current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ));
940
                if (current->timeout <= jiffies)
941
                        current->timeout = 0;
942
        }
943
 
944
        count = 0;
945
        wait_table.nr = 0;
946
        wait_table.entry = entry;
947
        wait = &wait_table;
948
 
949
        for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
950
                i = fdpnt->fd;
951
                fdpnt->revents = 0;
952
                if (!current->files->fd[i] || !current->files->fd[i]->f_inode)
953
                        fdpnt->revents = POLLNVAL;
954
        }
955
repeat:
956
        current->state = TASK_INTERRUPTIBLE;
957
        for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) {
958
                i = fdpnt->fd;
959
 
960
                if(i < 0) continue;
961
                if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue;
962
 
963
                if ((fdpnt->events & LINUX_POLLIN)
964
                && check(SEL_IN, wait, current->files->fd[i])) {
965
                        if (fdpnt->events & POLLIN)
966
                                retflag = POLLIN;
967
                        if (fdpnt->events & POLLRDNORM)
968
                                retflag = POLLRDNORM;
969
                        fdpnt->revents |= retflag;
970
                        count++;
971
                        wait = NULL;
972
                }
973
 
974
                if ((fdpnt->events & LINUX_POLLOUT) &&
975
                check(SEL_OUT, wait, current->files->fd[i])) {
976
                        fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events);
977
                        count++;
978
                        wait = NULL;
979
                }
980
 
981
                if (check(SEL_EX, wait, current->files->fd[i])) {
982
                        fdpnt->revents |= POLLHUP;
983
                        count++;
984
                        wait = NULL;
985
                }
986
        }
987
 
988
        if ((current->signal & (~current->blocked)))
989
                return -EINTR;
990
 
991
        wait = NULL;
992
        if (!count && current->timeout > jiffies) {
993
                schedule();
994
                goto repeat;
995
        }
996
 
997
        free_wait(&wait_table);
998
        free_page((unsigned long) entry);
999
 
1000
        /* OK, now copy the revents fields back to user space. */
1001
        fds1 = fds;
1002
        fdcount = 0;
1003
        for(i=0; i < (int)nfds; i++, ufds++, fds++) {
1004
                if (fds->revents) {
1005
                        fdcount++;
1006
                }
1007
                put_fs_word(fds->revents, &ufds->revents);
1008
        }
1009
        kfree(fds1);
1010
        current->timeout = 0;
1011
        current->state = TASK_RUNNING;
1012
        return fdcount;
1013
}
1014
 
1015
extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
1016
extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
1017
extern asmlinkage int sys_shmdt (char *shmaddr);
1018
extern asmlinkage int sys_shmget (key_t key, int size, int shmflg);
1019
 
1020
asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2,
1021
                            unsigned long arg3)
1022
{
1023
        unsigned long raddr;
1024
        int rval;
1025
 
1026
        switch(op) {
1027
        case 0:
1028
                /* sys_shmat(): attach a shared memory area */
1029
                rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr);
1030
                if(rval != 0)
1031
                        return rval;
1032
                return (int) raddr;
1033
        case 1:
1034
                /* sys_shmctl(): modify shared memory area attr. */
1035
                return sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3);
1036
        case 2:
1037
                /* sys_shmdt(): detach a shared memory area */
1038
                return sys_shmdt((char *)arg1);
1039
        case 3:
1040
                /* sys_shmget(): get a shared memory area */
1041
                return sys_shmget((key_t)arg1,(int)arg2,(int)arg3);
1042
        default:
1043
                return -EINVAL;
1044
        }
1045
}

powered by: WebSVN 2.1.0

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