📄 sys_sunos32.c
字号:
/* $Id: sys_sunos32.c,v 1.61 2001/08/13 14:40:07 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * * Based upon preliminary work which is: * * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/mman.h>#include <linux/mm.h>#include <linux/swap.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/resource.h>#include <linux/ipc.h>#include <linux/shm.h>#include <linux/msg.h>#include <linux/sem.h>#include <linux/signal.h>#include <linux/uio.h>#include <linux/utsname.h>#include <linux/major.h>#include <linux/stat.h>#include <linux/slab.h>#include <linux/pagemap.h>#include <linux/errno.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/pconf.h>#include <asm/idprom.h> /* for gethostid() */#include <asm/unistd.h>#include <asm/system.h>/* For the nfs mount emulation */#include <linux/socket.h>#include <linux/in.h>#include <linux/nfs.h>#include <linux/nfs2.h>#include <linux/nfs_mount.h>/* for sunos_select */#include <linux/time.h>#include <linux/personality.h>/* Use this to get at 32-bit user passed pointers. */#define A(__x) \({ unsigned long __ret; \ __asm__ ("srl %0, 0, %0" \ : "=r" (__ret) \ : "0" (__x)); \ __ret; \})#define SUNOS_NR_OPEN 256asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off){ struct file *file = NULL; unsigned long retval, ret_type; if(flags & MAP_NORESERVE) { static int cnt; if (cnt++ < 10) printk("%s: unimplemented SunOS MAP_NORESERVE mmap() flag\n", current->comm); flags &= ~MAP_NORESERVE; } retval = -EBADF; if(!(flags & MAP_ANONYMOUS)) { struct inode * inode; if(fd >= SUNOS_NR_OPEN) goto out; file = fget(fd); if (!file) goto out; inode = file->f_dentry->d_inode; if(MAJOR(inode->i_rdev)==MEM_MAJOR && MINOR(inode->i_rdev)==5) { flags |= MAP_ANONYMOUS; fput(file); file = NULL; } } retval = -EINVAL; if(!(flags & MAP_FIXED)) addr = 0; else if (len > 0xf0000000 || addr > 0xf0000000 - len) goto out_putf; ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); down_write(¤t->mm->mmap_sem); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, (unsigned long) off); up_write(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < 0xf0000000) ? 0 : retval);out_putf: if (file) fput(file);out: return (u32) retval;}asmlinkage int sunos_mctl(u32 addr, u32 len, int function, u32 arg){ return 0;}asmlinkage int sunos_brk(u32 baddr){ int freepages, retval = -ENOMEM; unsigned long rlim; unsigned long newbrk, oldbrk, brk = (unsigned long) baddr; down_write(¤t->mm->mmap_sem); if (brk < current->mm->end_code) goto out; newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(current->mm->brk); retval = 0; if (oldbrk == newbrk) { current->mm->brk = brk; goto out; } /* Always allow shrinking brk. */ if (brk <= current->mm->brk) { current->mm->brk = brk; do_munmap(current->mm, newbrk, oldbrk-newbrk); goto out; } /* Check against rlimit and stack.. */ retval = -ENOMEM; rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (brk - current->mm->end_code > rlim) goto out; /* Check against existing mmap mappings. */ if (find_vma_intersection(current->mm, oldbrk, newbrk+PAGE_SIZE)) goto out; /* stupid algorithm to decide if we have enough memory: while * simple, it hopefully works in most obvious cases.. Easy to * fool it, but this should catch most mistakes. */ freepages = atomic_read(&buffermem_pages) >> PAGE_SHIFT; freepages += atomic_read(&page_cache_size); freepages >>= 1; freepages += nr_free_pages(); freepages += nr_swap_pages; freepages -= num_physpages >> 4; freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; if (freepages < 0) goto out; /* Ok, we have probably got enough memory - let it rip. */ current->mm->brk = brk; do_brk(oldbrk, newbrk-oldbrk); retval = 0;out: up_write(¤t->mm->mmap_sem); return retval;}asmlinkage u32 sunos_sbrk(int increment){ int error, oldbrk; /* This should do it hopefully... */ oldbrk = (int)current->mm->brk; error = sunos_brk(((int) current->mm->brk) + increment); if(!error) error = oldbrk; return error;}asmlinkage u32 sunos_sstk(int increment){ printk("%s: Call to sunos_sstk(increment<%d>) is unsupported\n", current->comm, increment); return (u32)-1;}/* Give hints to the kernel as to what paging strategy to use... * Completely bogus, don't remind me. */#define VA_NORMAL 0 /* Normal vm usage expected */#define VA_ABNORMAL 1 /* Abnormal/random vm usage probable */#define VA_SEQUENTIAL 2 /* Accesses will be of a sequential nature */#define VA_INVALIDATE 3 /* Page table entries should be flushed ??? */static char *vstrings[] = { "VA_NORMAL", "VA_ABNORMAL", "VA_SEQUENTIAL", "VA_INVALIDATE",};asmlinkage void sunos_vadvise(u32 strategy){ static int count; /* I wanna see who uses this... */ if (count++ < 5) printk("%s: Advises us to use %s paging strategy\n", current->comm, strategy <= 3 ? vstrings[strategy] : "BOGUS");}/* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE * resource limit and is for backwards compatibility with older sunos * revs. */asmlinkage int sunos_getdtablesize(void){ return SUNOS_NR_OPEN;}#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))asmlinkage u32 sunos_sigblock(u32 blk_mask){ u32 old; spin_lock_irq(¤t->sigmask_lock); old = (u32) current->blocked.sig[0]; current->blocked.sig[0] |= (blk_mask & _BLOCKABLE); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return old;}asmlinkage u32 sunos_sigsetmask(u32 newmask){ u32 retval; spin_lock_irq(¤t->sigmask_lock); retval = (u32) current->blocked.sig[0]; current->blocked.sig[0] = (newmask & _BLOCKABLE); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return retval;}/* SunOS getdents is very similar to the newer Linux (iBCS2 compliant) *//* getdents system call, the format of the structure just has a different *//* layout (d_off+d_ino instead of d_ino+d_off) */struct sunos_dirent { s32 d_off; u32 d_ino; u16 d_reclen; u16 d_namlen; char d_name[1];};struct sunos_dirent_callback { struct sunos_dirent *curr; struct sunos_dirent *previous; int count; int error;};#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))#define ROUND_UP(x) (((x)+sizeof(s32)-1) & ~(sizeof(s32)-1))static int sunos_filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type){ struct sunos_dirent * dirent; struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->curr; buf->previous = dirent; put_user(ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); ((char *) dirent) += reclen; buf->curr = dirent; buf->count -= reclen; return 0;}asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt){ struct file * file; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; void *dirent = (void *)A(u_dirent); if(fd >= SUNOS_NR_OPEN) goto out; file = fget(fd); if(!file) goto out; error = -EINVAL; if(cnt < (sizeof(struct sunos_dirent) + 255)) goto out_putf; buf.curr = (struct sunos_dirent *) dirent; buf.previous = NULL; buf.count = cnt; buf.error = 0; error = vfs_readdir(file, sunos_filldir, &buf); if (error < 0) goto out_putf; lastdirent = buf.previous; error = buf.error; if (lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = cnt - buf.count; }out_putf: fput(file);out: return error;}/* Old sunos getdirentries, severely broken compatibility stuff here. */struct sunos_direntry { u32 d_ino; u16 d_reclen; u16 d_namlen; char d_name[1];};struct sunos_direntry_callback { struct sunos_direntry *curr; struct sunos_direntry *previous; int count; int error;};static int sunos_filldirentry(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type){ struct sunos_direntry * dirent; struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; dirent = buf->curr; buf->previous = dirent; put_user(ino, &dirent->d_ino); put_user(namlen, &dirent->d_namlen); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); ((char *) dirent) += reclen; buf->curr = dirent; buf->count -= reclen; return 0;}asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent, int cnt, u32 u_basep){ void *dirent = (void *) A(u_dirent); unsigned int *basep = (unsigned int *)A(u_basep); struct file * file; struct sunos_direntry * lastdirent; int error = -EBADF; struct sunos_direntry_callback buf; if(fd >= SUNOS_NR_OPEN) goto out; file = fget(fd); if(!file) goto out; error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) goto out_putf; buf.curr = (struct sunos_direntry *) dirent; buf.previous = NULL; buf.count = cnt; buf.error = 0; error = vfs_readdir(file, sunos_filldirentry, &buf); if (error < 0) goto out_putf; lastdirent = buf.previous; error = buf.error; if (lastdirent) { put_user(file->f_pos, basep); error = cnt - buf.count; }out_putf: fput(file);out: return error;}struct sunos_utsname { char sname[9]; char nname[9]; char nnext[56]; char rel[9]; char ver[9]; char mach[9];};asmlinkage int sunos_uname(struct sunos_utsname *name){ int ret; down_read(&uts_sem); ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); ret |= put_user('\0', &name->nname[8]); ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); up_read(&uts_sem); return (ret ? -EFAULT : 0);}asmlinkage int sunos_nosys(void){ struct pt_regs *regs;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -