URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [mips/] [kernel/] [syscall.c] - Rev 1777
Go to most recent revision | Compare with Previous | Blame | View Log
/* * MIPS specific syscall handling functions and syscalls * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1995 by Ralf Baechle */ #include <linux/linkage.h> #include <linux/mm.h> #include <linux/mman.h> #include <linux/sched.h> #include <linux/unistd.h> #include <asm/ptrace.h> #include <asm/segment.h> #include <asm/signal.h> extern asmlinkage void syscall_trace(void); typedef asmlinkage int (*syscall_t)(void *a0,...); extern asmlinkage int do_syscalls(struct pt_regs *regs, syscall_t fun, int narg); extern syscall_t sys_call_table[]; extern unsigned char sys_narg_table[]; asmlinkage int sys_pipe(struct pt_regs *regs) { int fd[2]; int error; error = do_pipe(fd); if (error) return error; regs->reg2 = fd[0]; regs->reg3 = fd[1]; return 0; } asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, int flags, int fd, off_t offset) { struct file * file = NULL; if (flags & MAP_RENAME) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); return do_mmap(file, addr, len, prot, flags, offset); } asmlinkage int sys_idle(void) { if (current->pid != 0) return -EPERM; /* endless idle loop with no priority at all */ current->counter = -100; for (;;) { /* * R4[26]00 have wait, R4[04]00 don't. */ if (wait_available && !need_resched) __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0\n\t"); schedule(); } } asmlinkage int sys_fork(struct pt_regs *regs) { return do_fork(SIGCHLD, regs->reg29, regs); } asmlinkage int sys_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; clone_flags = regs->reg4; newsp = regs->reg5; if (!newsp) newsp = regs->reg29; return do_fork(clone_flags, newsp, regs); } /* * sys_execve() executes a new program. */ asmlinkage int sys_execve(struct pt_regs *regs) { int error; char * filename; error = getname((char *) regs->reg4, &filename); if (error) return error; error = do_execve(filename, (char **) regs->reg5, (char **) regs->reg6, regs); putname(filename); return error; } /* * Do the indirect syscall syscall. */ asmlinkage int sys_syscall(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6) { syscall_t syscall; if (a0 > __NR_Linux + __NR_Linux_syscalls) return -ENOSYS; syscall = sys_call_table[a0]; /* * Prevent stack overflow by recursive * syscall(__NR_syscall, __NR_syscall,...); */ if (syscall == (syscall_t) sys_syscall) return -EINVAL; if (syscall == NULL) return -ENOSYS; return syscall((void *)a0, a1, a2, a3, a4, a5, a6); } void do_sys(struct pt_regs *regs) { unsigned long syscallnr, usp; syscall_t syscall; int errno, narg; /* * Compute the return address; */ if (regs->cp0_cause & CAUSEF_BD) { /* * This syscall is in a branch delay slot. Since we don't do * branch delay slot handling we would get a process trying * to do syscalls ever and ever again. So better zap it. */ printk("%s: syscall in branch delay slot.\n", current->comm); current->sig->action[SIGILL-1].sa_handler = NULL; current->blocked &= ~(1<<(SIGILL-1)); send_sig(SIGILL, current, 1); return; } regs->cp0_epc += 4; syscallnr = regs->reg2; if (syscallnr > (__NR_Linux + __NR_Linux_syscalls)) goto illegal_syscall; syscall = sys_call_table[syscallnr]; if (syscall == NULL) goto illegal_syscall; narg = sys_narg_table[syscallnr]; if (narg > 4) { /* * Verify that we can safely get the additional parameters * from the user stack. Of course I could read the params * from unaligned addresses ... Consider this a programming * course caliber .45. */ usp = regs->reg29; if (usp & 3) { printk("unaligned usp\n"); send_sig(SIGSEGV, current, 1); regs->reg2 = EFAULT; regs->reg7 = 1; return; } errno = verify_area(VERIFY_READ, (void *) (usp + 16), (narg - 4) * sizeof(unsigned long)); if (errno < 0) goto bad_syscall; } if ((current->flags & PF_TRACESYS) == 0) { errno = do_syscalls(regs, syscall, narg); if (errno < 0 || current->errno) goto bad_syscall; regs->reg2 = errno; regs->reg7 = 0; } else { syscall_trace(); errno = do_syscalls(regs, syscall, narg); if (errno < 0 || current->errno) { regs->reg2 = -errno; regs->reg7 = 1; } else { regs->reg2 = errno; regs->reg7 = 0; } syscall_trace(); } return; bad_syscall: regs->reg2 = -errno; regs->reg7 = 1; return; illegal_syscall: regs->reg2 = ENOSYS; regs->reg7 = 1; return; }
Go to most recent revision | Compare with Previous | Blame | View Log