patch-1.3.48 linux/arch/mips/kernel/syscall.c

Next file: linux/arch/mips/kernel/syscalls.h
Previous file: linux/arch/mips/kernel/signal.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.47/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
@@ -0,0 +1,225 @@
+/*
+ * 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 savely 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;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this