sys_syscall patch.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The 'sys_syscall' syscall isn't properly implemented in the 64-bit
kernel (for o32 as well as n64).
Below is a patch, it seems to work for in the o32 case, but I haven't
tested the n64 version (obviously).

/Carsten


--
_    _ ____  ___   Carsten Langgaard   Mailto:carstenl@mips.com
|\  /|||___)(___   MIPS Denmark        Direct: +45 4486 5527
| \/ |||    ____)  Lautrupvang 4B      Switch: +45 4486 5555
  TECHNOLOGIES     2750 Ballerup       Fax...: +45 4486 5556
                   Denmark             http://www.mips.com


Index: arch/mips64/kernel//linux32.c
===================================================================
RCS file: /home/repository/sw/linux-2.4.18/arch/mips64/kernel/linux32.c,v
retrieving revision 1.3
diff -u -r1.3 linux32.c
--- arch/mips64/kernel//linux32.c	13 Jun 2002 09:08:02 -0000	1.3
+++ arch/mips64/kernel//linux32.c	24 Jun 2002 08:56:02 -0000
@@ -32,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <asm/mman.h>
 #include <asm/ipc.h>
+#include <asm/unistd.h>
 
 
 #define A(__x) ((unsigned long)(__x))
@@ -872,6 +873,82 @@
 		oldalarm++;
 
 	return oldalarm;
+}
+
+typedef asmlinkage long (*syscall_t)(void *a0,...);
+extern syscall_t sys32_call_table[];
+extern unsigned char sys32_narg_table[];
+
+/*
+ * Do the indirect syscall syscall.
+ * Don't care about kernel locking; the actual syscall will do it.
+ *
+ * XXX This is broken.
+ */
+asmlinkage int sys32_syscall(abi64_no_regargs, struct pt_regs regs)
+{
+	syscall_t syscall;
+	unsigned long syscallnr = regs.regs[4];
+	unsigned long a0, a1, a2, a3, a4, a5, a6;
+	int nargs, errno;
+
+	if ((syscallnr < __NR_Linux32) || 
+	    (syscallnr > __NR_Linux32 + __NR_Linux32_syscalls))
+		return -ENOSYS;
+
+	syscall = sys32_call_table[syscallnr-__NR_Linux32];
+	nargs = sys32_narg_table[syscallnr-__NR_Linux32];
+
+	/*
+	 * Prevent stack overflow by recursive
+	 * syscall(__NR_syscall, __NR_syscall,...);
+	 */
+	if (syscall == (syscall_t) sys32_syscall) {
+		return -EINVAL;
+	}
+
+	if (syscall == NULL) {
+		return -ENOSYS;
+	}
+
+	if(nargs > 3) {
+		unsigned long usp = regs.regs[29];
+		unsigned long *sp = (unsigned long *) usp;
+		if(usp & 3) {
+			printk("unaligned usp -EFAULT\n");
+			force_sig(SIGSEGV, current);
+			return -EFAULT;
+		}
+		errno = verify_area(VERIFY_READ, (void *) (usp + 16),
+		                    (nargs - 3) * sizeof(unsigned long));
+		if(errno) {
+			return -EFAULT;
+		}
+		switch(nargs) {
+		case 7:
+			a3 = sp[4]; a4 = sp[5]; a5 = sp[6]; a6 = sp[7];
+			break;
+		case 6:
+			a3 = sp[4]; a4 = sp[5]; a5 = sp[6]; a6 = 0;
+			break;
+		case 5:
+			a3 = sp[4]; a4 = sp[5]; a5 = a6 = 0;
+			break;
+		case 4:
+			a3 = sp[4]; a4 = a5 = a6 = 0;
+			break;
+
+		default:
+			a3 = a4 = a5 = a6 = 0;
+			break;
+		}
+	} else {
+		a3 = a4 = a5 = a6 = 0;
+	}
+	a0 = regs.regs[5]; a1 = regs.regs[6]; a2 = regs.regs[7];
+	if(nargs == 0)
+		a0 = (unsigned long) &regs;
+	return syscall((void *)a0, a1, a2, a3, a4, a5, a6);
 }
 
 /* Translations due to time_t size differences.  Which affects all
Index: arch/mips64/kernel//scall_64.S
===================================================================
RCS file: /home/repository/sw/linux-2.4.18/arch/mips64/kernel/scall_64.S,v
retrieving revision 1.3
diff -u -r1.3 scall_64.S
--- arch/mips64/kernel//scall_64.S	19 Jun 2002 07:04:08 -0000	1.3
+++ arch/mips64/kernel//scall_64.S	24 Jun 2002 08:10:23 -0000
@@ -132,7 +132,7 @@
 	j	ret_from_sys_call
 	END(handle_sys64)
 
-sys_call_table:
+EXPORT(sys_call_table)
 	PTR	sys_syscall				/* 5000 */
 	PTR	sys_exit
 	PTR	sys_fork
Index: arch/mips64/kernel//scall_o32.S
===================================================================
RCS file: /home/repository/sw/linux-2.4.18/arch/mips64/kernel/scall_o32.S,v
retrieving revision 1.3
diff -u -r1.3 scall_o32.S
--- arch/mips64/kernel//scall_o32.S	19 Jun 2002 07:04:08 -0000	1.3
+++ arch/mips64/kernel//scall_o32.S	24 Jun 2002 08:53:48 -0000
@@ -52,8 +52,8 @@
 
 	/* XXX Put both in one cacheline, should save a bit. */
 	dsll	t0, v0, 3		# offset into table
-	ld	t2, (sys_call_table - (__NR_Linux32 * 8))(t0) # syscall routine
-	lbu	t3, (sys_narg_table - __NR_Linux32)(v0)	# number of arguments
+	ld	t2, (sys32_call_table - (__NR_Linux32 * 8))(t0) # syscall routine
+	lbu	t3, (sys32_narg_table - __NR_Linux32)(v0)	# number of arguments
 
 	subu	t0, t3, 5		# 5 or more arguments?
 	sd	a3, PT_R26(sp)		# save a3 for syscall restarting
@@ -246,7 +246,7 @@
 	END(sys_sysmips)
 
 	.macro	syscalltable
-	sys	sys_syscall	0			/* 4000 */
+	sys	sys32_syscall	0			/* 4000 */
 	sys	sys_exit	1
 	sys	sys_fork	0
 	sys	sys_read	3
@@ -489,12 +489,12 @@
 	PTR	\function
 	.endm
 
-sys_call_table:
+EXPORT(sys32_call_table)
 	syscalltable
 
 	.macro	sys function, nargs
 	.byte	\nargs
 	.endm
-
-sys_narg_table:
+	
+EXPORT(sys32_narg_table)
 	syscalltable
Index: arch/mips64/kernel//syscall.c
===================================================================
RCS file: /home/repository/sw/linux-2.4.18/arch/mips64/kernel/syscall.c,v
retrieving revision 1.2
diff -u -r1.2 syscall.c
--- arch/mips64/kernel//syscall.c	13 Jun 2002 09:08:02 -0000	1.2
+++ arch/mips64/kernel//syscall.c	24 Jun 2002 08:38:55 -0000
@@ -123,14 +123,41 @@
 	return error;
 }
 
+typedef asmlinkage long (*syscall_t)(void *a0,...);
+extern syscall_t sys_call_table[];
+
 /*
  * Do the indirect syscall syscall.
- *
- * XXX This is borken.
+ * Don't care about kernel locking; the actual syscall will do it.
  */
 asmlinkage int sys_syscall(abi64_no_regargs, struct pt_regs regs)
 {
-	return -ENOSYS;
+	syscall_t syscall;
+	unsigned long syscallnr = regs.regs[4];
+	unsigned long a0, a1, a2, a3, a4, a5, a6;
+
+	if ((syscallnr < __NR_Linux) || 
+	    (syscallnr > __NR_Linux + __NR_Linux_syscalls))
+		return -ENOSYS;
+
+	syscall = sys_call_table[syscallnr-__NR_Linux];
+
+	/*
+	 * Prevent stack overflow by recursive
+	 * syscall(__NR_syscall, __NR_syscall,...);
+	 */
+	if (syscall == (syscall_t) sys_syscall) {
+		return -EINVAL;
+	}
+
+	if (syscall == NULL) {
+		return -ENOSYS;
+	}
+
+	a0 = regs.regs[5]; a1 = regs.regs[6]; a2 = regs.regs[7];
+	a3 = regs.regs[8]; a4 = regs.regs[9]; a5 = regs.regs[10];
+	a6 = regs.regs[11];
+	return syscall((void *)a0, a1, a2, a3, a4, a5, a6);
 }
 
 asmlinkage int

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux