summaryrefslogtreecommitdiff
path: root/src/libc/thread.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/libc/thread.S')
-rw-r--r--src/libc/thread.S40
1 files changed, 40 insertions, 0 deletions
diff --git a/src/libc/thread.S b/src/libc/thread.S
new file mode 100644
index 0000000..2900544
--- /dev/null
+++ b/src/libc/thread.S
@@ -0,0 +1,40 @@
+#define ASM_FILE 1
+#include <camellia/syscalls.h>
+#include <camellia/flags.h>
+
+.section .text
+.global thread_creates
+.type thread_creates, @function
+// void thread_creates(int flags, void (*fn)(void*), void *arg, void *stack);
+thread_creates:
+ push %r12
+ push %r13
+ push %r14
+
+ /* save fn, arg, stack */
+ mov %rsi, %r12
+ mov %rdx, %r13
+ mov %rcx, %r14
+
+ mov %rdi, %rsi
+ or $(FORK_SHAREMEM | FORK_SHAREHANDLE), %rsi
+ mov $_SYS_FORK, %rdi
+ xor %rdx, %rdx
+ syscall
+
+ test %rax, %rax
+ jz 1f
+ /* in parent, return normally */
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
+1: /* in child */
+ mov %r14, %rsp
+ mov %r13, %rdi
+ call *%r12
+
+ mov $_SYS_EXIT, %rdi
+ xor %rsi, %rsi
+ syscall
+ hlt /* if all else fails... */