Add support for riscv64

Change-Id: Icf8e7adc033339b538310a819f5001d480de0288
Reviewed-on: https://chromium-review.googlesource.com/c/linux-syscall-support/+/3599251
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/linux_syscall_support.h b/linux_syscall_support.h
index d3791cd..a48e6fe 100644
--- a/linux_syscall_support.h
+++ b/linux_syscall_support.h
@@ -88,7 +88,8 @@
  */
 #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) ||   \
      defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \
-     defined(__aarch64__) || defined(__s390__) || defined(__e2k__))  \
+     defined(__aarch64__) || defined(__s390__) || defined(__e2k__) ||  \
+     (defined(__riscv) && __riscv_xlen == 64))                         \
   && (defined(__linux) || defined(__ANDROID__))
 
 #ifndef SYS_CPLUSPLUS
@@ -302,8 +303,8 @@
 } __attribute__((packed,aligned(4)));
 #elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
   #define kernel_old_sigaction kernel_sigaction
-#elif defined(__aarch64__)
-  // No kernel_old_sigaction defined for arm64.
+#elif defined(__aarch64__) || defined(__riscv)
+  // No kernel_old_sigaction defined for arm64 or riscv.
 #endif
 
 /* Some kernel functions (e.g. sigaction() in 2.6.23) require that the
@@ -342,7 +343,9 @@
     void             (*sa_sigaction_)(int, siginfo_t *, void *);
   };
   unsigned long      sa_flags;
+#ifndef __riscv
   void               (*sa_restorer)(void);
+#endif
   struct kernel_sigset_t sa_mask;
 #endif
 };
@@ -542,7 +545,7 @@
   int                st_blocks;
   int                st_pad4[14];
 };
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || defined(__riscv)
 struct kernel_stat {
   unsigned long      st_dev;
   unsigned long      st_ino;
@@ -1110,7 +1113,7 @@
 #define __NR_getrandom          (__NR_SYSCALL_BASE + 384)
 #endif
 /* End of ARM 3/EABI definitions                                             */
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || defined(__riscv)
 #ifndef __NR_setxattr
 #define __NR_setxattr             5
 #endif
@@ -1926,7 +1929,7 @@
   #undef  LSS_RETURN
   #if defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \
        || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) \
-       || defined(__e2k__)
+       || defined(__e2k__) || defined(__riscv)
   /* Failing system calls return a negative result in the range of
    * -1..-4095. These are "errno" values with the sign inverted.
    */
@@ -3419,6 +3422,122 @@
       }
       LSS_RETURN(int, __ret);
     }
+  #elif defined(__riscv) && __riscv_xlen == 64
+    #undef LSS_REG
+    #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a
+    #undef  LSS_BODY
+    #define LSS_BODY(type,name,args...)                                       \
+          register int64_t __res_a0 __asm__("a0");                            \
+          register int64_t __a7 __asm__("a7") = __NR_##name;                  \
+          int64_t __res;                                                      \
+          __asm__ __volatile__ ("scall\n"                                     \
+                                : "=r"(__res_a0)                              \
+                                : "r"(__a7) , ## args                         \
+                                : "memory");                                  \
+          __res = __res_a0;                                                   \
+          LSS_RETURN(type, __res)
+    #undef _syscall0
+    #define _syscall0(type, name)                                             \
+      type LSS_NAME(name)(void) {                                             \
+        LSS_BODY(type, name);                                                 \
+      }
+    #undef _syscall1
+    #define _syscall1(type, name, type1, arg1)                                \
+      type LSS_NAME(name)(type1 arg1) {                                       \
+        LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0));                    \
+      }
+    #undef _syscall2
+    #define _syscall2(type, name, type1, arg1, type2, arg2)                   \
+      type LSS_NAME(name)(type1 arg1, type2 arg2) {                           \
+        LSS_REG(0, arg1); LSS_REG(1, arg2);                                   \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1));                           \
+      }
+    #undef _syscall3
+    #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3)      \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) {               \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2));                \
+      }
+    #undef _syscall4
+    #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)  \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {   \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_REG(3, arg4);                                                     \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3));     \
+      }
+    #undef _syscall5
+    #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,  \
+                      type5,arg5)                                             \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4,     \
+                          type5 arg5) {                                       \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_REG(3, arg4); LSS_REG(4, arg5);                                   \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),      \
+                             "r"(__r4));                                      \
+      }
+    #undef _syscall6
+    #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,  \
+                      type5,arg5,type6,arg6)                                  \
+      type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4,     \
+                          type5 arg5, type6 arg6) {                           \
+        LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3);                 \
+        LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6);                 \
+        LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),      \
+                             "r"(__r4), "r"(__r5));                           \
+      }
+
+    LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
+                                   int flags, void *arg, int *parent_tidptr,
+                                   void *newtls, int *child_tidptr) {
+      int64_t __res;
+      {
+        register int64_t __res_a0 __asm__("a0");
+        register uint64_t __flags __asm__("a0") = flags;
+        register void *__stack __asm__("a1") = child_stack;
+        register void *__ptid  __asm__("a2") = parent_tidptr;
+        register void *__tls   __asm__("a3") = newtls;
+        register int  *__ctid  __asm__("a4") = child_tidptr;
+        __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be
+                              * used by the child.
+                              */
+                             "addi    %2,%2,-16\n"
+                             "sd      %1, 0(%2)\n"
+                             "sd      %4, 8(%2)\n"
+
+                             /* %a0 = syscall(%a0 = flags,
+                              *               %a1 = child_stack,
+                              *               %a2 = parent_tidptr,
+                              *               %a3 = newtls,
+                              *               %a4 = child_tidptr)
+                              */
+                             "li      a7, %8\n"
+                             "scall\n"
+
+                             /* if (%a0 != 0)
+                              *   return %a0;
+                              */
+                             "bnez    %0, 1f\n"
+
+                             /* In the child, now. Call "fn(arg)".
+                              */
+                             "ld      a1, 0(sp)\n"
+                             "ld      a0, 8(sp)\n"
+                             "jalr    a1\n"
+
+                             /* Call _exit(%a0).
+                              */
+                             "li      a7, %9\n"
+                             "scall\n"
+                           "1:\n"
+                             : "=r" (__res_a0)
+                             : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
+                               "r"(__ptid), "r"(__tls), "r"(__ctid),
+                               "i"(__NR_clone), "i"(__NR_exit)
+                             : "cc", "memory");
+        __res = __res_a0;
+      }
+      LSS_RETURN(int, __res);
+    }
   #elif defined(__e2k__)
 
     #undef _LSS_BODY
@@ -4484,7 +4603,7 @@
       LSS_SC_BODY(4, int, 8, d, type, protocol, sv);
     }
   #endif
-  #if defined(__ARM_EABI__) || defined (__aarch64__)
+  #if defined(__ARM_EABI__) || defined (__aarch64__) || defined(__riscv)
     LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg,
                          int, flags)
     LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*,
@@ -4812,7 +4931,7 @@
 // TODO: define this in an arch-independant way instead of inlining the clone
 //       syscall body.
 
-# if defined(__aarch64__)
+# if defined(__aarch64__) || defined(__riscv)
   LSS_INLINE pid_t LSS_NAME(fork)(void) {
     // No fork syscall on aarch64 - implement by means of the clone syscall.
     // Note that this does not reset glibc's cached view of the PID/TID, so