Add a sys_clone3 wrapper (based on the INLINE_CLONE_SYSCALL macro
in glibc) for SPARC to handle its unique return call convention.

The needed handling is described in arch/sparc/kernel/process_{32|64}.c:

Parent -->  %o0 == child's  pid, %o1 == 0
Child  -->  %o0 == parent's pid, %o1 == 1

Signed-off-by: Ludwig Rydberg <[email protected]>
---
 .../selftests/clone3/clone3_selftests.h       | 75 +++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/tools/testing/selftests/clone3/clone3_selftests.h 
b/tools/testing/selftests/clone3/clone3_selftests.h
index a0593e8950f0..5fa33294227d 100644
--- a/tools/testing/selftests/clone3/clone3_selftests.h
+++ b/tools/testing/selftests/clone3/clone3_selftests.h
@@ -33,12 +33,87 @@ struct __clone_args {
        __aligned_u64 cgroup;
 };
 
+#if defined(__sparc__)
+#include <errno.h>
+
+#if    defined(__arch64__)
+#define __SYSCALL_STRING                                               \
+       "mov    %[scn], %%g1;"                                          \
+       "ta     0x6d;"                                                  \
+       "bcc,pt %%xcc, 1f;"                                             \
+       " nop;"                                                         \
+       "sub    %%g0, %%o0, %%o0;"                                      \
+       "1:"
+
+#define __SYSCALL_CLOBBERS                                             \
+       "g1", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",           \
+       "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",           \
+       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",         \
+       "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",         \
+       "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",         \
+       "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",         \
+       "cc", "memory"
+#else
+#define __SYSCALL_STRING                                               \
+       "mov    %[scn], %%g1;"                                          \
+       "ta     0x10;"                                                  \
+       "bcc    1f;"                                                    \
+       " nop;"                                                         \
+       "sub    %%g0, %%o0, %%o0;"                                      \
+       "1:"
+
+#define __SYSCALL_CLOBBERS                                             \
+       "g1", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",           \
+       "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",           \
+       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",         \
+       "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",         \
+       "cc", "memory"
+#endif
+
+/* A special wrapper is required to handle the return call convention
+ * on SPARC and is based on the INLINE_CLONE_SYSCALL macro in glibc.
+ *
+ * Parent -->  %o0 == child's  pid, %o1 == 0
+ * Child  -->  %o0 == parent's pid, %o1 == 1
+ */
+static inline pid_t sparc_clone3(struct __clone_args *args, size_t size)
+{
+       long _cl_args = (long) (args);
+       long _size = (long) (size);
+       long _scn = __NR_clone3;
+
+       register long o0 __asm__ ("o0") = _cl_args;
+       register long o1 __asm__ ("o1") = _size;
+
+       asm volatile (__SYSCALL_STRING
+                       : "=r" (o0), "=r" (o1)
+                       : [scn] "r" (_scn), "0" (o0), "1" (o1)
+                       : __SYSCALL_CLOBBERS);
+
+       if ((unsigned long) (o0) > -4096UL) {
+               errno = -o0;
+               o0 = -1L;
+       } else {
+               o0 &= (o1 - 1);
+       }
+
+       return o0;
+}
+
+static pid_t sys_clone3(struct __clone_args *args, size_t size)
+{
+       fflush(stdout);
+       fflush(stderr);
+       return sparc_clone3(args, size);
+}
+#else
 static pid_t sys_clone3(struct __clone_args *args, size_t size)
 {
        fflush(stdout);
        fflush(stderr);
        return syscall(__NR_clone3, args, size);
 }
+#endif
 
 static inline void test_clone3_supported(void)
 {
-- 
2.35.3


Reply via email to