📄 sysirix.c
字号:
/* * sysirix.c: IRIX system call emulation. * * Copyright (C) 1996 David S. Miller * Copyright (C) 1997 Miguel de Icaza * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/binfmts.h>#include <linux/capability.h>#include <linux/highuid.h>#include <linux/pagemap.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/slab.h>#include <linux/swap.h>#include <linux/errno.h>#include <linux/time.h>#include <linux/timex.h>#include <linux/times.h>#include <linux/elf.h>#include <linux/msg.h>#include <linux/shm.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/utsname.h>#include <linux/file.h>#include <linux/vfs.h>#include <linux/namei.h>#include <linux/socket.h>#include <linux/security.h>#include <linux/syscalls.h>#include <asm/ptrace.h>#include <asm/page.h>#include <asm/uaccess.h>#include <asm/inventory.h>/* 2,191 lines of complete and utter shit coming up... */extern int max_threads;/* The sysmp commands supported thus far. */#define MP_NPROCS 1 /* # processor in complex */#define MP_NAPROCS 2 /* # active processors in complex */#define MP_PGSIZE 14 /* Return system page size in v1. */asmlinkage int irix_sysmp(struct pt_regs *regs){ unsigned long cmd; int base = 0; int error = 0; if(regs->regs[2] == 1000) base = 1; cmd = regs->regs[base + 4]; switch(cmd) { case MP_PGSIZE: error = PAGE_SIZE; break; case MP_NPROCS: case MP_NAPROCS: error = num_online_cpus(); break; default: printk("SYSMP[%s:%d]: Unsupported opcode %d\n", current->comm, current->pid, (int)cmd); error = -EINVAL; break; } return error;}/* The prctl commands. */#define PR_MAXPROCS 1 /* Tasks/user. */#define PR_ISBLOCKED 2 /* If blocked, return 1. */#define PR_SETSTACKSIZE 3 /* Set largest task stack size. */#define PR_GETSTACKSIZE 4 /* Get largest task stack size. */#define PR_MAXPPROCS 5 /* Num parallel tasks. */#define PR_UNBLKONEXEC 6 /* When task exec/exit's, unblock. */#define PR_SETEXITSIG 8 /* When task exit's, set signal. */#define PR_RESIDENT 9 /* Make task unswappable. */#define PR_ATTACHADDR 10 /* (Re-)Connect a vma to a task. */#define PR_DETACHADDR 11 /* Disconnect a vma from a task. */#define PR_TERMCHILD 12 /* Kill child if the parent dies. */#define PR_GETSHMASK 13 /* Get the sproc() share mask. */#define PR_GETNSHARE 14 /* Number of share group members. */#define PR_COREPID 15 /* Add task pid to name when it core. */#define PR_ATTACHADDRPERM 16 /* (Re-)Connect vma, with specified prot. */#define PR_PTHREADEXIT 17 /* Kill a pthread, only for IRIX 6.[234] */asmlinkage int irix_prctl(unsigned option, ...){ va_list args; int error = 0; va_start(args, option); switch (option) { case PR_MAXPROCS: printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n", current->comm, current->pid); error = max_threads; break; case PR_ISBLOCKED: { struct task_struct *task; printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n", current->comm, current->pid); read_lock(&tasklist_lock); task = find_task_by_pid(va_arg(args, pid_t)); error = -ESRCH; if (error) error = (task->run_list.next != NULL); read_unlock(&tasklist_lock); /* Can _your_ OS find this out that fast? */ break; } case PR_SETSTACKSIZE: { long value = va_arg(args, long); printk("irix_prctl[%s:%d]: Wants PR_SETSTACKSIZE<%08lx>\n", current->comm, current->pid, (unsigned long) value); if (value > RLIM_INFINITY) value = RLIM_INFINITY; if (capable(CAP_SYS_ADMIN)) { task_lock(current->group_leader); current->signal->rlim[RLIMIT_STACK].rlim_max = current->signal->rlim[RLIMIT_STACK].rlim_cur = value; task_unlock(current->group_leader); error = value; break; } task_lock(current->group_leader); if (value > current->signal->rlim[RLIMIT_STACK].rlim_max) { error = -EINVAL; task_unlock(current->group_leader); break; } current->signal->rlim[RLIMIT_STACK].rlim_cur = value; task_unlock(current->group_leader); error = value; break; } case PR_GETSTACKSIZE: printk("irix_prctl[%s:%d]: Wants PR_GETSTACKSIZE\n", current->comm, current->pid); error = current->signal->rlim[RLIMIT_STACK].rlim_cur; break; case PR_MAXPPROCS: printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n", current->comm, current->pid); error = 1; break; case PR_UNBLKONEXEC: printk("irix_prctl[%s:%d]: Wants PR_UNBLKONEXEC\n", current->comm, current->pid); error = -EINVAL; break; case PR_SETEXITSIG: printk("irix_prctl[%s:%d]: Wants PR_SETEXITSIG\n", current->comm, current->pid); /* We can probably play some game where we set the task * exit_code to some non-zero value when this is requested, * and check whether exit_code is already set in do_exit(). */ error = -EINVAL; break; case PR_RESIDENT: printk("irix_prctl[%s:%d]: Wants PR_RESIDENT\n", current->comm, current->pid); error = 0; /* Compatibility indeed. */ break; case PR_ATTACHADDR: printk("irix_prctl[%s:%d]: Wants PR_ATTACHADDR\n", current->comm, current->pid); error = -EINVAL; break; case PR_DETACHADDR: printk("irix_prctl[%s:%d]: Wants PR_DETACHADDR\n", current->comm, current->pid); error = -EINVAL; break; case PR_TERMCHILD: printk("irix_prctl[%s:%d]: Wants PR_TERMCHILD\n", current->comm, current->pid); error = -EINVAL; break; case PR_GETSHMASK: printk("irix_prctl[%s:%d]: Wants PR_GETSHMASK\n", current->comm, current->pid); error = -EINVAL; /* Until I have the sproc() stuff in. */ break; case PR_GETNSHARE: error = 0; /* Until I have the sproc() stuff in. */ break; case PR_COREPID: printk("irix_prctl[%s:%d]: Wants PR_COREPID\n", current->comm, current->pid); error = -EINVAL; break; case PR_ATTACHADDRPERM: printk("irix_prctl[%s:%d]: Wants PR_ATTACHADDRPERM\n", current->comm, current->pid); error = -EINVAL; break; default: printk("irix_prctl[%s:%d]: Non-existant opcode %d\n", current->comm, current->pid, option); error = -EINVAL; break; } va_end(args); return error;}#undef DEBUG_PROCGRPSextern unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt);extern int getrusage(struct task_struct *p, int who, struct rusage __user *ru);extern char *prom_getenv(char *name);extern long prom_setenv(char *name, char *value);/* The syssgi commands supported thus far. */#define SGI_SYSID 1 /* Return unique per-machine identifier. */#define SGI_INVENT 5 /* Fetch inventory */# define SGI_INV_SIZEOF 1# define SGI_INV_READ 2#define SGI_RDNAME 6 /* Return string name of a process. */#define SGI_SETNVRAM 8 /* Set PROM variable. */#define SGI_GETNVRAM 9 /* Get PROM variable. */#define SGI_SETPGID 21 /* Set process group id. */#define SGI_SYSCONF 22 /* POSIX sysconf garbage. */#define SGI_PATHCONF 24 /* POSIX sysconf garbage. */#define SGI_SETGROUPS 40 /* POSIX sysconf garbage. */#define SGI_GETGROUPS 41 /* POSIX sysconf garbage. */#define SGI_RUSAGE 56 /* BSD style rusage(). */#define SGI_SSYNC 62 /* Synchronous fs sync. */#define SGI_GETSID 65 /* SysVr4 get session id. */#define SGI_ELFMAP 68 /* Map an elf image. */#define SGI_TOSSTSAVE 108 /* Toss saved vma's. */#define SGI_FP_BCOPY 129 /* Should FPU bcopy be used on this machine? */#define SGI_PHYSP 1011 /* Translate virtual into physical page. */asmlinkage int irix_syssgi(struct pt_regs *regs){ unsigned long cmd; int retval, base = 0; if (regs->regs[2] == 1000) base = 1; cmd = regs->regs[base + 4]; switch(cmd) { case SGI_SYSID: { char __user *buf = (char __user *) regs->regs[base + 5]; /* XXX Use ethernet addr.... */ retval = clear_user(buf, 64) ? -EFAULT : 0; break; }#if 0 case SGI_RDNAME: { int pid = (int) regs->regs[base + 5]; char __user *buf = (char __user *) regs->regs[base + 6]; struct task_struct *p; char tcomm[sizeof(current->comm)]; read_lock(&tasklist_lock); p = find_task_by_pid(pid); if (!p) { read_unlock(&tasklist_lock); retval = -ESRCH; break; } get_task_comm(tcomm, p); read_unlock(&tasklist_lock); /* XXX Need to check sizes. */ retval = copy_to_user(buf, tcomm, sizeof(tcomm)) ? -EFAULT : 0; break; } case SGI_GETNVRAM: { char __user *name = (char __user *) regs->regs[base+5]; char __user *buf = (char __user *) regs->regs[base+6]; char *value; return -EINVAL; /* til I fix it */ value = prom_getenv(name); /* PROM lock? */ if (!value) { retval = -EINVAL; break; } /* Do I strlen() for the length? */ retval = copy_to_user(buf, value, 128) ? -EFAULT : 0; break; } case SGI_SETNVRAM: { char __user *name = (char __user *) regs->regs[base+5]; char __user *value = (char __user *) regs->regs[base+6]; return -EINVAL; /* til I fix it */ retval = prom_setenv(name, value); /* XXX make sure retval conforms to syssgi(2) */ printk("[%s:%d] setnvram(\"%s\", \"%s\"): retval %d", current->comm, current->pid, name, value, retval);/* if (retval == PROM_ENOENT) retval = -ENOENT; */ break; }#endif case SGI_SETPGID: {#ifdef DEBUG_PROCGRPS printk("[%s:%d] setpgid(%d, %d) ", current->comm, current->pid, (int) regs->regs[base + 5], (int)regs->regs[base + 6]);#endif retval = sys_setpgid(regs->regs[base + 5], regs->regs[base + 6]);#ifdef DEBUG_PROCGRPS printk("retval=%d\n", retval);#endif } case SGI_SYSCONF: { switch(regs->regs[base + 5]) { case 1: retval = (MAX_ARG_PAGES >> 4); /* XXX estimate... */ goto out; case 2: retval = max_threads; goto out; case 3: retval = HZ; goto out; case 4: retval = NGROUPS_MAX; goto out; case 5: retval = NR_OPEN; goto out; case 6: retval = 1; goto out; case 7: retval = 1; goto out; case 8: retval = 199009; goto out; case 11: retval = PAGE_SIZE; goto out; case 12: retval = 4; goto out; case 25: case 26: case 27: case 28: case 29: case 30: retval = 0; goto out; case 31: retval = 32; goto out; default: retval = -EINVAL; goto out; }; } case SGI_SETGROUPS: retval = sys_setgroups((int) regs->regs[base + 5], (gid_t __user *) regs->regs[base + 6]); break; case SGI_GETGROUPS: retval = sys_getgroups((int) regs->regs[base + 5], (gid_t __user *) regs->regs[base + 6]); break; case SGI_RUSAGE: { struct rusage __user *ru = (struct rusage __user *) regs->regs[base + 6]; switch((int) regs->regs[base + 5]) { case 0: /* rusage self */ retval = getrusage(current, RUSAGE_SELF, ru); goto out; case -1: /* rusage children */ retval = getrusage(current, RUSAGE_CHILDREN, ru); goto out; default: retval = -EINVAL; goto out; }; } case SGI_SSYNC: sys_sync(); retval = 0; break; case SGI_GETSID:#ifdef DEBUG_PROCGRPS printk("[%s:%d] getsid(%d) ", current->comm, current->pid, (int) regs->regs[base + 5]);#endif retval = sys_getsid(regs->regs[base + 5]);#ifdef DEBUG_PROCGRPS printk("retval=%d\n", retval);#endif break; case SGI_ELFMAP: retval = irix_mapelf((int) regs->regs[base + 5], (struct elf_phdr __user *) regs->regs[base + 6], (int) regs->regs[base + 7]); break; case SGI_TOSSTSAVE: /* XXX We don't need to do anything? */ retval = 0; break; case SGI_FP_BCOPY: retval = 0; break; case SGI_PHYSP: { unsigned long addr = regs->regs[base + 5]; int __user *pageno = (int __user *) (regs->regs[base + 6]); struct mm_struct *mm = current->mm; pgd_t *pgdp; pud_t *pudp; pmd_t *pmdp; pte_t *ptep; down_read(&mm->mmap_sem); pgdp = pgd_offset(mm, addr); pudp = pud_offset(pgdp, addr); pmdp = pmd_offset(pudp, addr); ptep = pte_offset(pmdp, addr); retval = -EINVAL; if (ptep) { pte_t pte = *ptep; if (pte_val(pte) & (_PAGE_VALID | _PAGE_PRESENT)) { /* b0rked on 64-bit */ retval = put_user((pte_val(pte) & PAGE_MASK) >> PAGE_SHIFT, pageno); } } up_read(&mm->mmap_sem); break; } case SGI_INVENT: { int arg1 = (int) regs->regs [base + 5]; void __user *buffer = (void __user *) regs->regs [base + 6]; int count = (int) regs->regs [base + 7]; switch (arg1) { case SGI_INV_SIZEOF: retval = sizeof (inventory_t); break; case SGI_INV_READ: retval = dump_inventory_to_user (buffer, count); break; default: retval = -EINVAL; } break; } default: printk("irix_syssgi: Unsupported command %d\n", (int)cmd); retval = -EINVAL; break; };out: return retval;}asmlinkage int irix_gtime(struct pt_regs *regs){ return get_seconds();}/* * IRIX is completely broken... it returns 0 on success, otherwise * ENOMEM. */asmlinkage int irix_brk(unsigned long brk){ unsigned long rlim; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; int ret; down_write(&mm->mmap_sem); if (brk < mm->end_code) { ret = -ENOMEM; goto out; } newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(mm->brk); if (oldbrk == newbrk) { mm->brk = brk;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -