linux-mips
[Top] [All Lists]

sys_syscall patch.

To: Ralf Baechle <ralf@oss.sgi.com>, linux-mips@oss.sgi.com
Subject: sys_syscall patch.
From: Carsten Langgaard <carstenl@mips.com>
Date: Mon, 24 Jun 2002 11:07:24 +0200
Sender: owner-linux-mips@oss.sgi.com
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
<Prev in Thread] Current Thread [Next in Thread>