[MIPS] Add support for MIPS syscalls

Change-Id: I4deba67e15c865c4c2db03064c04098a09828ea6
Signed-off-by: Raghu Gandham <raghu@mips.com>
Signed-off-by: Chris Dearman <chris@mips.com>
diff --git a/libc/tools/bionic_utils.py b/libc/tools/bionic_utils.py
index 0bc947b..abb7820 100644
--- a/libc/tools/bionic_utils.py
+++ b/libc/tools/bionic_utils.py
@@ -4,13 +4,13 @@
 
 # support Bionic architectures, add new ones as appropriate
 #
-bionic_archs = [ "arm", "x86" ]
+bionic_archs = [ "arm", "x86", "mips" ]
 
 # basic debugging trace support
 # call D_setlevel to set the verbosity level
 # and D(), D2(), D3(), D4() to add traces
 #
-verbose = 1
+verbose = 0
 
 def D(msg):
     global verbose
@@ -178,7 +178,7 @@
         self.syscalls = []
         self.lineno   = 0
 
-    def E(msg):
+    def E(self, msg):
         print "%d: %s" % (self.lineno, msg)
 
     def parse_line(self, line):
@@ -238,36 +238,55 @@
 
         number = line[pos_rparen+1:].strip()
         if number == "stub":
-            syscall_id  = -1
-            syscall_id2 = -1
+            syscall_common = -1
+            syscall_arm  = -1
+            syscall_x86 = -1
+            syscall_mips = -1
         else:
             try:
                 if number[0] == '#':
                     number = number[1:].strip()
                 numbers = string.split(number,',')
-                syscall_id  = int(numbers[0])
-                syscall_id2 = syscall_id
-                if len(numbers) > 1:
-                    syscall_id2 = int(numbers[1])
+                if len(numbers) == 1:
+                    syscall_common = int(numbers[0])
+                    syscall_arm = -1
+                    syscall_x86 = -1
+                    syscall_mips = -1
+                else:
+                    if len(numbers) == 3:
+                        syscall_common = -1
+                        syscall_arm  = int(numbers[0])
+                        syscall_x86 = int(numbers[1])
+                        syscall_mips = int(numbers[2])
+                    else:
+                        E("invalid syscall number format in '%s'" % line)
+                        return
             except:
                 E("invalid syscall number in '%s'" % line)
                 return
 
-		global verbose
+        global verbose
         if verbose >= 2:
-            if call_id < 0:
-                print "%s: %d,%d" % (syscall_name, syscall_id, syscall_id2)
+            if call_id == -1:
+                if syscall_common == -1:
+                    print "%s: %d,%d,%d" % (syscall_name, syscall_arm, syscall_x86, syscall_mips)
+                else:
+                    print "%s: %d" % (syscall_name, syscall_common)
             else:
-                print "%s(%d): %d,%d" % (syscall_name, call_id, syscall_id, syscall_id2)
+                if syscall_common == -1:
+                    print "%s(%d): %d,%d,%d" % (syscall_name, call_id, syscall_arm, syscall_x86, syscall_mips)
+                else:
+                    print "%s(%d): %d" % (syscall_name, call_id, syscall_common)
 
-        t = { "id"     : syscall_id,
-              "id2"    : syscall_id2,
+        t = { "armid"  : syscall_arm,
+              "x86id"  : syscall_x86,
+              "mipsid" : syscall_mips,
+              "common" : syscall_common,
               "cid"    : call_id,
               "name"   : syscall_name,
               "func"   : syscall_func,
               "params" : syscall_params,
               "decl"   : "%-15s  %s (%s);" % (return_type, syscall_func, params) }
-
         self.syscalls.append(t)
 
     def parse_file(self, file_path):
diff --git a/libc/tools/checksyscalls.py b/libc/tools/checksyscalls.py
index 2c563d7..286e727 100755
--- a/libc/tools/checksyscalls.py
+++ b/libc/tools/checksyscalls.py
@@ -70,10 +70,17 @@
 re_nr_clock_line = re.compile( r"#define __NR_(\w*)\s*\(__NR_timer_create\+(\w*)\)" )
 re_arm_nr_line   = re.compile( r"#define __ARM_NR_(\w*)\s*\(__ARM_NR_BASE\+\s*(\w*)\)" )
 re_x86_line      = re.compile( r"#define __NR_(\w*)\s*([0-9]*)" )
+re_mips_line     = re.compile( r"#define __NR_(\w*)\s*\(__NR_Linux\s*\+\s*([0-9]*)\)" )
 
 # now read the Linux arm header
 def process_nr_line(line,dict):
 
+    m = re_mips_line.match(line)
+    if m:
+        if dict["Linux"]==4000:
+            dict[m.group(1)] = int(m.group(2))
+        return
+
     m = re_nr_line.match(line)
     if m:
         dict[m.group(1)] = int(m.group(2))
@@ -118,6 +125,7 @@
 
 arm_dict = {}
 x86_dict = {}
+mips_dict = {}
 
 # remove trailing slash from the linux_root, if any
 if linux_root[-1] == '/':
@@ -141,8 +149,15 @@
         print "maybe using a different set of kernel headers might help."
         sys.exit(1)
 
+mips_unistd = find_arch_header(linux_root, "mips", "unistd.h")
+if not mips_unistd:
+    print "WEIRD: Could not locate the Mips unistd.h kernel header file,"
+    print "maybe using a different set of kernel headers might help."
+    sys.exit(1)
+
 process_header( arm_unistd, arm_dict )
 process_header( x86_unistd, x86_dict )
+process_header( mips_unistd, mips_dict )
 
 # now perform the comparison
 errors = 0
@@ -154,18 +169,19 @@
         sc_id   = sc[idname]
         if sc_id >= 0:
             if not arch_dict.has_key(sc_name):
-                print "%s syscall %s not defined, should be %d !!" % (archname, sc_name, sc_id)
+                print "error: %s syscall %s not defined, should be %d" % (archname, sc_name, sc_id)
                 errors += 1
             elif not arch_dict.has_key(sc_name):
-                print "%s syscall %s is not implemented!" % (archname, sc_name)
+                print "error: %s syscall %s is not implemented" % (archname, sc_name)
                 errors += 1
             elif arch_dict[sc_name] != sc_id:
-                print "%s syscall %s should be %d instead of %d !!" % (archname, sc_name, arch_dict[sc_name], sc_id)
+                print "error: %s syscall %s should be %d instead of %d" % (archname, sc_name, arch_dict[sc_name], sc_id)
                 errors += 1
     return errors
 
-errors += check_syscalls("arm", "id", arm_dict)
-errors += check_syscalls("x86", "id2", x86_dict)
+errors += check_syscalls("arm", "armid", arm_dict)
+errors += check_syscalls("x86", "x86id", x86_dict)
+errors += check_syscalls("mips", "mipsid", mips_dict)
 
 if errors == 0:
     print "congratulations, everything's fine !!"
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index bed9445..947e444 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -1,11 +1,12 @@
 #!/usr/bin/python
 #
-# this tool is used to generate the syscall assmbler templates
-# to be placed into arch-x86/syscalls, as well as the content
-# of arch-x86/linux/_syscalls.h
+# this tool is used to generate the syscall assembler templates
+# to be placed into arch-{arm,x86,mips}/syscalls, as well as the content
+# of arch-{arm,x86,mips}/linux/_syscalls.h
 #
 
 import sys, os.path, glob, re, commands, filecmp, shutil
+import getpass
 
 from bionic_utils import *
 
@@ -31,9 +32,10 @@
 bionic_temp = "/tmp/bionic_gensyscalls/"
 
 # all architectures, update as you see fit
-all_archs = [ "arm", "x86" ]
+all_archs = [ "arm", "x86", "mips" ]
 
 def make_dir( path ):
+    path = os.path.abspath(path)
     if not os.path.exists(path):
         parent = os.path.dirname(path)
         if parent:
@@ -183,6 +185,32 @@
     .fnend
 """
 
+# mips assembler templates for each syscall stub
+#
+mips_call = """/* autogenerated by gensyscalls.py */
+#include <sys/linux-syscalls.h>
+    .text
+    .globl %(fname)s
+    .align 4
+    .ent %(fname)s
+
+%(fname)s:
+    .set noreorder
+    .cpload $t9
+    li $v0, %(idname)s
+    syscall
+    bnez $a3, 1f
+    move $a0, $v0
+    j $ra
+    nop
+1:
+    la $t9,__set_errno
+    j $t9
+    nop
+    .set reorder
+    .end %(fname)s
+"""
+
 def param_uses_64bits(param):
     """Returns True iff a syscall parameter description corresponds
        to a 64-bit type."""
@@ -331,6 +359,10 @@
                 return thumb_call_long % t
         return thumb_call_default % t
 
+    def mips_genstub(self,fname, idname):
+        t = { "fname"  : fname,
+              "idname" : idname }
+        return mips_call % t
 
     def superh_genstub(self, fname, flags, idname):
         numargs = int(flags)
@@ -360,7 +392,7 @@
             syscall_params = t["params"]
             syscall_name   = t["name"]
 
-            if t["id"] >= 0:
+            if t["common"] >= 0 or t["armid"] >= 0:
                 num_regs = count_arm_param_registers(syscall_params)
                 if gen_thumb_stubs:
                     t["asm-thumb"] = self.thumb_genstub(syscall_func,num_regs,"__NR_"+syscall_name)
@@ -370,7 +402,7 @@
                     else:
                         t["asm-arm"]   = self.arm_genstub(syscall_func,num_regs,"__NR_"+syscall_name)
 
-            if t["id2"] >= 0:
+            if t["common"] >= 0 or t["x86id"] >= 0:
                 num_regs = count_generic_param_registers(syscall_params)
                 if t["cid"] >= 0:
                     t["asm-x86"] = self.x86_genstub_cid(syscall_func, num_regs, "__NR_"+syscall_name, t["cid"])
@@ -380,62 +412,70 @@
                 E("cid for dispatch syscalls is only supported for x86 in "
                   "'%s'" % syscall_name)
                 return
+            if t["common"] >= 0 or t["mipsid"] >= 0:
+                t["asm-mips"] = self.mips_genstub(syscall_func,"__NR_"+syscall_name)
 
 
     def gen_NR_syscall(self,fp,name,id):
         fp.write( "#define __NR_%-25s    (__NR_SYSCALL_BASE + %d)\n" % (name,id) )
 
-    # now dump the content of linux/_syscalls.h
+    # now dump the content of linux-syscalls.h
     def gen_linux_syscalls_h(self):
         path = "include/sys/linux-syscalls.h"
         D( "generating "+path )
         fp = create_file( path )
         fp.write( "/* auto-generated by gensyscalls.py, do not touch */\n" )
         fp.write( "#ifndef _BIONIC_LINUX_SYSCALLS_H_\n\n" )
-        fp.write( "#if !defined __ASM_ARM_UNISTD_H && !defined __ASM_I386_UNISTD_H\n" )
+        fp.write( "#if !defined __ASM_ARM_UNISTD_H && !defined __ASM_I386_UNISTD_H && !defined __ASM_MIPS_UNISTD_H\n" )
         fp.write( "#if defined __arm__ && !defined __ARM_EABI__ && !defined __thumb__\n" )
-        fp.write( "  #  define __NR_SYSCALL_BASE  0x900000\n" )
-        fp.write( "  #else\n" )
-        fp.write( "  #  define  __NR_SYSCALL_BASE  0\n" )
-        fp.write( "  #endif\n\n" )
+        fp.write( "  #  define __NR_SYSCALL_BASE 0x900000\n" )
+        fp.write( "#elif defined(__mips__)\n" )
+        fp.write( "  #  define __NR_SYSCALL_BASE 4000\n" )
+        fp.write( "#else\n" )
+        fp.write( "  #  define __NR_SYSCALL_BASE 0\n" )
+        fp.write( "#endif\n\n" )
 
         # first, all common syscalls
-        for sc in self.syscalls:
-            sc_id  = sc["id"]
-            sc_id2 = sc["id2"]
+        for sc in sorted(self.syscalls,key=lambda x:x["common"]):
+            sc_id  = sc["common"]
             sc_name = sc["name"]
-            if sc_id == sc_id2 and sc_id >= 0:
+            if sc_id >= 0:
                 self.gen_NR_syscall( fp, sc_name, sc_id )
 
         # now, all arm-specific syscalls
         fp.write( "\n#ifdef __arm__\n" );
         for sc in self.syscalls:
-            sc_id  = sc["id"]
-            sc_id2 = sc["id2"]
+            sc_id  = sc["armid"]
             sc_name = sc["name"]
-            if sc_id != sc_id2 and sc_id >= 0:
+            if sc_id >= 0:
                 self.gen_NR_syscall( fp, sc_name, sc_id )
         fp.write( "#endif\n" );
 
         gen_syscalls = {}
         # finally, all i386-specific syscalls
         fp.write( "\n#ifdef __i386__\n" );
-        for sc in self.syscalls:
-            sc_id  = sc["id"]
-            sc_id2 = sc["id2"]
+        for sc in sorted(self.syscalls,key=lambda x:x["x86id"]):
+            sc_id  = sc["x86id"]
             sc_name = sc["name"]
-            if sc_id != sc_id2 and sc_id2 >= 0 and sc_name not in gen_syscalls:
-                self.gen_NR_syscall( fp, sc_name, sc_id2 )
+            if sc_id >= 0 and sc_name not in gen_syscalls:
+                self.gen_NR_syscall( fp, sc_name, sc_id )
                 gen_syscalls[sc_name] = True
         fp.write( "#endif\n" );
 
+        # all mips-specific syscalls
+        fp.write( "\n#ifdef __mips__\n" );
+        for sc in sorted(self.syscalls,key=lambda x:x["mipsid"]):
+            sc_id = sc["mipsid"]
+            if sc_id >= 0:
+                self.gen_NR_syscall( fp, sc["name"], sc_id )
+        fp.write( "#endif\n" );
+
         fp.write( "\n#endif\n" )
         fp.write( "\n#endif /* _BIONIC_LINUX_SYSCALLS_H_ */\n" );
         fp.close()
         self.other_files.append( path )
 
-
-    # now dump the content of linux/_syscalls.h
+    # now dump the content of linux-syscalls.h
     def gen_linux_unistd_h(self):
         path = "include/sys/linux-unistd.h"
         D( "generating "+path )
@@ -462,6 +502,7 @@
         arch_test = {
             "arm": lambda x: x.has_key("asm-arm") or x.has_key("asm-thumb"),
             "x86": lambda x: x.has_key("asm-x86"),
+            "mips": lambda x: x.has_key("asm-mips")
         }
 
         for sc in self.syscalls:
@@ -471,6 +512,7 @@
         fp.close()
         self.other_files.append( path )
 
+
     # now generate each syscall stub
     def gen_syscall_stubs(self):
         for sc in self.syscalls:
@@ -498,6 +540,13 @@
                 fp.close()
                 self.new_stubs.append( fname )
 
+            if sc.has_key("asm-mips") and 'mips' in all_archs:
+                fname = "arch-mips/syscalls/%s.S" % sc["func"]
+                D2( ">>> generating "+fname )
+                fp = create_file( fname )
+                fp.write(sc["asm-mips"])
+                fp.close()
+                self.new_stubs.append( fname )
 
     def  regenerate(self):
         D( "scanning for existing architecture-specific stub files" )
@@ -515,7 +564,7 @@
 
         if not os.path.exists( bionic_temp ):
             D( "creating %s" % bionic_temp )
-            os.mkdir( bionic_temp )
+            make_dir( bionic_temp )
 
 #        D( "p4 editing source files" )
 #        for arch in all_archs: