]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
lib/posix-process: Add `libc` system call wrapper for `clone`
authorSergiu Moga <sergiu@unikraft.io>
Mon, 24 Mar 2025 16:52:48 +0000 (18:52 +0200)
committerUnikraft Bot <monkey@unikraft.io>
Thu, 17 Apr 2025 12:33:46 +0000 (12:33 +0000)
In order to successfully call the clone system call through a libc
wrapper we need to be able to have an assembly sequence that both
translates the arguments passed by the libc wrapper to those of the
underlying syscall, since their signatures differ, as well as redirect
the parent and child accordingly upon exit from said syscall: child
must run its requested function and argument and parent must return
to the clone caller with an unscathed register context.

Said assembly sequence must be aware of the signature differences
between architectures, e.g. ARM64 vs x86_64 signatures of the
clone system call.

Signed-off-by: Sergiu Moga <sergiu@unikraft.io>
Approved-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Andrei Tatar <andrei@unikraft.io>
GitHub-Closes: #1618

lib/posix-process/Makefile.uk
lib/posix-process/arch/arm64/clone.S [new file with mode: 0644]
lib/posix-process/arch/x86_64/clone.S [new file with mode: 0644]
lib/posix-process/clone.c

index 1d5b7e00d2c0b694d02fbc9a05539d244fb005b8..440f0824d1545faf2a630cdd29eee42043270fde 100644 (file)
@@ -42,6 +42,7 @@ LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_SIGNAL) += $(LIBPOSIX_PROCESS_BA
 endif
 
 LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/clone.c
+LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/arch/$(CONFIG_UK_ARCH)/clone.S|arch
 LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/clonetab.ld
 LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/arch/$(CONFIG_UK_ARCH)/clone.c|$(CONFIG_UK_ARCH)
 CFLAGS-$(CONFIG_LIBPOSIX_PROCESS_PIDS) += -fno-builtin-exit -fno-builtin-exit-group
diff --git a/lib/posix-process/arch/arm64/clone.S b/lib/posix-process/arch/arm64/clone.S
new file mode 100644 (file)
index 0000000..55c783a
--- /dev/null
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <uk/syscall.h>
+
+/*
+ * NOTE: We need to replicate this assembly libc wrapper in our
+ * supported/ported external libc libraries (e.g. musl) because their
+ * wrappers do not typically tailor to our use case of having system calls
+ * regular function calls.
+ *
+ * Whenever porting a new libc library, make sure to replicate this code there
+ * as well, unless the library in question does somehow indeed have a more
+ * special wrapper that still allows our clone functionality to still work
+ * correctly.
+ */
+#if UK_LIBC_SYSCALLS
+.global clone
+clone:
+       /* Save fn and arg in callee-saved registers, but first make sure
+        * we can also restore them before returning in the parent.
+        */
+       stp     x20, x21, [sp, #-16]
+       mov     x20, x0
+       mov     x21, x3
+
+       /* Now reorder arguments */
+
+       /* flags */
+       mov     x0, x2
+
+       /* stack is already in x1 */
+
+       /* parent_tid */
+       mov     x2, x4
+
+       /* tls */
+       mov     x3, x5
+
+       /* child_tid */
+       mov     x4, x6
+
+       bl      uk_syscall_e_clone
+
+       /* Let the parent just return */
+       cbnz    x0, 1f
+
+       /* Mark the outermost frame (avoid unwinding beyond this) */
+       mov     x29, xzr
+
+       /* The child should now just call the saved fn(arg) */
+       mov     x0, x21
+       blr     x20
+
+       /* If managed to return from fn(arg) we must call exit(x0) */
+       bl      uk_syscall_e_exit
+
+0:
+       /* Put a wfi safeguard here, just in care, cus exit is noreturn */
+       wfi
+       b       0b
+
+1:
+       /* Restore the registers saved in the beginning */
+       ldp     x20, x21, [sp, #-16]
+       ret
+#endif /* UK_LIBC_SYSCALLS */
diff --git a/lib/posix-process/arch/x86_64/clone.S b/lib/posix-process/arch/x86_64/clone.S
new file mode 100644 (file)
index 0000000..b57003a
--- /dev/null
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <uk/syscall.h>
+
+/*
+ * NOTE: We need to replicate this assembly libc wrapper in our
+ * supported/ported external libc libraries (e.g. musl) because their
+ * wrappers do not typically tailor to our use case of having system calls
+ * regular function calls.
+ *
+ * Whenever porting a new libc library, make sure to replicate this code there
+ * as well, unless the library in question does somehow indeed have a more
+ * special wrapper that still allows our clone functionality to still work
+ * correctly.
+ */
+#if UK_LIBC_SYSCALLS
+.global clone
+clone:
+       /* Save fn and arg in callee-saved registers, but first make sure
+        * we can also restore them before returning in the parent.
+        */
+       pushq   %rbx
+       pushq   %rbp
+       movq    %rdi, %rbx
+       movq    %rcx, %rbp
+
+       /* Now reorder arguments */
+       /* flags */
+       movq    %rdx, %rdi
+
+       /* stack is already in rsi */
+
+       /* parent_tid */
+       movq    %r8, %rdx
+
+       /* child_tid: this is passed on the stack as it does not fit
+        * in the registers used for the arguments
+        *
+        * NOTE: Although this runs on native builds (syscall == function call),
+        * we mustn't use rcx for the 4th argument like for a regular function
+        * call but instead we will have to use r10 as is supposed to happen
+        * for system calls. This is because `clone` is registered as an
+        * execenv system call and execenv registrations assume that the
+        * 4th argument is that according to the syscall calling convention.
+        */
+       movq    24(%rsp), %r10
+
+       /* tls */
+       movq    %r9, %r8
+
+       call    uk_syscall_e_clone
+
+       /* Let the parent just return */
+       test    %eax, %eax
+       jnz     1f
+
+       /* The child should now just call the saved fn(arg) */
+       movq    %rbp, %rdi
+
+       /* Mark the outermost frame (avoid unwinding beyond this) */
+       xorl    %ebp, %ebp
+       call    *%rbx
+
+       /* If managed to return from fn(arg) we must call exit(rax) */
+       movq    %rax, %rdi
+       call    uk_syscall_e_exit
+
+0:
+       /* Put a hlt safeguard here, just in care, cus exit is noreturn */
+       hlt
+       jmp     0b
+1:
+       /* Restore the registers saved in the beginning */
+       popq    %rbp
+       popq    %rbx
+       ret
+#endif /* UK_LIBC_SYSCALLS */
index 55314ff9650745b08806b0a9c4b46d6c39ea97dc..01f7e490ffa2ced42301f7dc539ea23a7f3b7a39 100644 (file)
@@ -590,17 +590,6 @@ UK_LLSYSCALL_R_E_DEFINE(int, clone,
        return uk_clone(&cl_args, sizeof(cl_args), execenv);
 }
 
-#if UK_LIBC_SYSCALLS
-int clone(int (*fn)(void *) __unused, void *sp __unused,
-         int flags __unused, void *arg __unused,
-         ... /* pid_t *parent_tid, void *tls, pid_t *child_tid */)
-{
-       /* TODO */
-       errno = EINVAL;
-       return -1;
-}
-#endif /* UK_LIBC_SYSCALLS */
-
 /*
  * Checks that the CLONE_VM is set so that we make sure that
  * the address space is shared. Unikraft does currently not support