📄 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/pagemap.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/slab.h>#include <linux/swap.h>#include <linux/errno.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 <asm/ptrace.h>#include <asm/page.h>#include <asm/pgalloc.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 = smp_num_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 /* When parent sleeps with fishes, kill child. */#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 without prejudice. */asmlinkage int irix_prctl(struct pt_regs *regs){ unsigned long cmd; int error = 0, base = 0; if (regs->regs[2] == 1000) base = 1; cmd = regs->regs[base + 4]; switch (cmd) { 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(regs->regs[base + 5]); 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 = regs->regs[base + 5]; 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)) { current->rlim[RLIMIT_STACK].rlim_max = current->rlim[RLIMIT_STACK].rlim_cur = value; error = value; break; } if (value > current->rlim[RLIMIT_STACK].rlim_max) { error = -EINVAL; break; } current->rlim[RLIMIT_STACK].rlim_cur = value; error = value; break; } case PR_GETSTACKSIZE: printk("irix_prctl[%s:%d]: Wants PR_GETSTACKSIZE\n", current->comm, current->pid); error = current->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; case PR_PTHREADEXIT: printk("irix_prctl[%s:%d]: Wants PR_PTHREADEXIT\n", current->comm, current->pid); do_exit(regs->regs[base + 5]); default: printk("irix_prctl[%s:%d]: Non-existant opcode %d\n", current->comm, current->pid, (int)cmd); error = -EINVAL; break; } return error;}#undef DEBUG_PROCGRPSextern unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt);extern asmlinkage int sys_setpgid(pid_t pid, pid_t pgid);extern void sys_sync(void);extern asmlinkage int sys_getsid(pid_t pid);extern asmlinkage long sys_write (unsigned int fd, const char *buf, unsigned long count);extern asmlinkage long sys_lseek (unsigned int fd, off_t offset, unsigned int origin);extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);extern int getrusage(struct task_struct *p, int who, struct rusage *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 *buf = (char *) regs->regs[base + 5]; /* XXX Use ethernet addr.... */ retval = clear_user(buf, 64); break; }#if 0 case SGI_RDNAME: { int pid = (int) regs->regs[base + 5]; char *buf = (char *) regs->regs[base + 6]; struct task_struct *p; char comm[16]; retval = verify_area(VERIFY_WRITE, buf, 16); if (retval) break; read_lock(&tasklist_lock); p = find_task_by_pid(pid); if (!p) { read_unlock(&tasklist_lock); retval = -ESRCH; break; } memcpy(comm, p->comm, 16); read_unlock(&tasklist_lock); /* XXX Need to check sizes. */ copy_to_user(buf, p->comm, 16); retval = 0; break; } case SGI_GETNVRAM: { char *name = (char *) regs->regs[base+5]; char *buf = (char *) regs->regs[base+6]; char *value; return -EINVAL; /* til I fix it */ retval = verify_area(VERIFY_WRITE, buf, 128); if (retval) break; value = prom_getenv(name); /* PROM lock? */ if (!value) { retval = -EINVAL; break; } /* Do I strlen() for the length? */ copy_to_user(buf, value, 128); retval = 0; break; } case SGI_SETNVRAM: { char *name = (char *) regs->regs[base+5]; char *value = (char *) 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; 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 *) regs->regs[base + 6]); break; case SGI_GETGROUPS: retval = sys_getgroups((int) regs->regs[base + 5], (gid_t *) regs->regs[base + 6]); break; case SGI_RUSAGE: { struct rusage *ru = (struct rusage *) 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 *) 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 *pageno = (int *) (regs->regs[base + 6]); struct mm_struct *mm = current->mm; pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; retval = verify_area(VERIFY_WRITE, pageno, sizeof(int)); if (retval) return retval; down_read(&mm->mmap_sem); pgdp = pgd_offset(mm, addr); pmdp = pmd_offset(pgdp, addr); ptep = pte_offset(pmdp, addr); retval = -EINVAL; if (ptep) { pte_t pte = *ptep; if (pte_val(pte) & (_PAGE_VALID | _PAGE_PRESENT)) { 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 *buffer = (void *) 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 CURRENT_TIME;}int vm_enough_memory(long pages);/* * 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; ret = 0; goto out; } /* * Always allow shrinking brk */ if (brk <= mm->brk) { mm->brk = brk; do_munmap(mm, newbrk, oldbrk-newbrk); ret = 0; goto out; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -