Index: uspace/lib/c/arch/abs32le/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/abs32le/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,17 @@
 #define _LIBC_abs32le_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	sp[-1] = (uintptr_t) arg;
+	sp[-2] = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/abs32le/src/thread_entry.c
===================================================================
--- uspace/lib/c/arch/abs32le/src/thread_entry.c	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/abs32le/src/thread_entry.c	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -30,4 +30,5 @@
  */
 
+#include <stdbool.h>
 #include <stddef.h>
 #include "../../../generic/private/thread.h"
@@ -35,5 +36,6 @@
 void __thread_entry(void)
 {
-	__thread_main(NULL);
+	while (true)
+		;
 }
 
Index: uspace/lib/c/arch/amd64/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/amd64/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/amd64/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,19 @@
 #define _LIBC_amd64_THREAD_H_
 
+#include <align.h>
+#include <stddef.h>
+#include <stdint.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	*--sp = (uintptr_t) arg;
+	*--sp = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/amd64/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/amd64/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/amd64/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,4 +35,8 @@
 #
 SYMBOL_BEGIN(__thread_entry)
+	# Pop libc thread entry function and argument
+	popq %rax
+	popq %rdi
+
 	#
 	# Create the first stack frame.
@@ -42,8 +46,4 @@
 	movq %rsp, %rbp
 
-	#
-	# RAX contains address of uarg
-	#
-	movq %rax, %rdi
-	call FUNCTION_REF(__thread_main)
+	call *%rax
 SYMBOL_END(__thread_entry)
Index: uspace/lib/c/arch/arm32/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/arm32/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/arm32/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -37,4 +37,17 @@
 #define _LIBC_arm32_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	*--sp = (uintptr_t) main;
+	*--sp = (uintptr_t) arg;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/arm32/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/arm32/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/arm32/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,4 +35,7 @@
 #
 SYMBOL(__thread_entry)
+	# Pop libc entry function and its argument.
+	pop { r0, r4 }
+
 	#
 	# Create the first stack frame.
@@ -43,3 +46,3 @@
 	sub fp, ip, #4
 
-	b __thread_main
+	bx r4
Index: uspace/lib/c/arch/arm64/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/arm64/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/arm64/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,17 @@
 #define _LIBC_arm64_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	*--sp = (uintptr_t) arg;
+	*--sp = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/arm64/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/arm64/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/arm64/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,10 +35,11 @@
 #
 SYMBOL(__thread_entry)
-	#
+	# Load entry function and argument from stack.
+	ldp x1, x0, [sp], #16
+
 	# Create the first stack frame.
-	#
 	mov x29, #0
 	stp x29, x30, [sp, #-16]!
 	mov x29, sp
 
-	b __thread_main
+	br x1
Index: uspace/lib/c/arch/ia32/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/ia32/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ia32/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,19 @@
 #define _LIBC_ia32_THREAD_H_
 
+#include <align.h>
+#include <stddef.h>
+#include <stdint.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	*--sp = (uintptr_t) arg;
+	*--sp = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/ia32/src/syscall.S
===================================================================
--- uspace/lib/c/arch/ia32/src/syscall.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ia32/src/syscall.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -77,5 +77,4 @@
 	pushl %ebp
 	mov %esp, %ebp
-	lea ra, %edi
 	movl 20(%esp), %edx	# First argument.
 	movl 24(%esp), %ecx	# Second argument.
@@ -83,6 +82,5 @@
 	movl 32(%esp), %esi	# Fourth argument.
 	movl 44(%esp), %eax	# Syscall number.
-	sysenter
-ra:
+	call 1f
 	movw %cs, %cx
 	addw $8, %cx
@@ -95,3 +93,8 @@
 	popl %ebx
 	ret
+
+	/* Trampoline for entering kernel */
+1:
+	pop %edi
+	sysenter
 FUNCTION_END(__syscall_fast)
Index: uspace/lib/c/arch/ia32/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/ia32/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ia32/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -41,4 +41,9 @@
 	# Do not set %gs, it contains descriptor that can see TLS
 
+	# Pop libc thread main function.
+	popl %eax
+	# Pop argument.
+	popl %ebx
+
 	#
 	# Create the first stack frame.
@@ -48,9 +53,6 @@
 	mov %esp, %ebp
 
-	#
-	# EAX contains address of uarg.
-	#
-	pushl %eax
-	call __thread_main
+	pushl %ebx
+	call *%eax
 
 	#
Index: uspace/lib/c/arch/ia64/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/ia64/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ia64/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,18 @@
 #define _LIBC_ia64_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) (ALIGN_DOWN((uintptr_t) stack + stack_size / 2, 16));
+
+	/* Store data under stack pointer */
+	sp[-1] = (uintptr_t) arg;
+	sp[-2] = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/ia64/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/ia64/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ia64/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -37,16 +37,18 @@
 	alloc loc0 = ar.pfs, 0, 1, 1, 0
 
-#ifndef CONFIG_RTLD
-	# XXX This does not work in a shared library
-	movl gp = __gp
-#endif
+	add r8 = -8, sp ;;
+	# Entry function argument
+	ld8 out0 = [r8], -8 ;;
 
-	#
-	# r8 contains address of uarg structure.
-	#
+	# Entry function descriptor
+	ld8 r8 = [r8] ;;
+	# Entry function address
+	ld8 r9 = [r8], 8 ;;
+	# Entry function global pointer
+	ld8 gp = [r8] ;;
 
-	mov out0 = r8 ;;
-	# XXX br.call.sptk.many b0 = FUNCTION_REF(__thread_main)
-	br.call.sptk.many b0 = __thread_main
+	mov b1 = r9 ;;
+
+	br.call.sptk.many b0 = b1 ;;
 
 	#
Index: uspace/lib/c/arch/mips32/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/mips32/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/mips32/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -37,4 +37,17 @@
 #define _LIBC_mips32_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	sp[-1] = (uintptr_t) arg;
+	sp[-2] = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/mips32/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/mips32/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/mips32/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -40,25 +40,12 @@
 #
 SYMBOL(__thread_entry)
-	.ent __thread_entry
-	.frame $sp, ABI_STACK_FRAME, $ra
-	.cpload $t9
+	# All registers should be zero, including $fp and $ra.
+	# Instead of setting up a stack frame here, we leave it for __thread_main.
 
-	#
-	# v0 contains address of uarg.
-	#
-	add $a0, $v0, 0
+	# Function argument.
+	lw $a0, -4($sp)
+	# Function pointer.
+	lw $t0, -8($sp)
 
-	# Allocate the stack frame.
-	addiu $sp, -ABI_STACK_FRAME
-
-	# Allow PIC code
-	.cprestore 16
-
-	jal __thread_main
+	j $t0
 	nop
-
-	#
-	# Not reached.
-	#
-	addiu $sp, ABI_STACK_FRAME
-	.end __thread_entry
Index: uspace/lib/c/arch/ppc32/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ppc32/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,18 @@
 #define _LIBC_ppc32_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size - sizeof(void *), 16);
+
+	sp[0] = 0;
+	sp[-1] = (uintptr_t) arg;
+	sp[-2] = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/ppc32/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/ppc32/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/ppc32/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,11 +35,12 @@
 #
 SYMBOL(__thread_entry)
-	#
-	# Create the first stack frame.
-	#
-	li %r4, 0
-	stw %r4, 0(%r1)
-	stwu %r1, -16(%r1)
+	# Load function and argument.
+	lwz %r3, -4(%r1)
+	lwz %r4, -8(%r1)
 
-	b __thread_main
+	# Clear LR
+	li %r0, 0
+	mtlr %r0
 
+	mtctr %r4
+	bctr
Index: uspace/lib/c/arch/riscv64/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/riscv64/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/riscv64/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -36,4 +36,17 @@
 #define _LIBC_riscv64_THREAD_H_
 
+#include <align.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size, 16);
+
+	sp[-1] = (uintptr_t) arg;
+	sp[-2] = (uintptr_t) main;
+
+	return (uintptr_t) sp;
+}
+
 #endif
 
Index: uspace/lib/c/arch/riscv64/src/thread_entry.c
===================================================================
--- uspace/lib/c/arch/riscv64/src/thread_entry.c	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/riscv64/src/thread_entry.c	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,5 +35,7 @@
 void __thread_entry(void)
 {
-	__thread_main((void *) 0);
+	// TODO
+	while (true)
+		;
 }
 
Index: uspace/lib/c/arch/sparc64/include/libarch/thread.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/libarch/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/sparc64/include/libarch/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,4 +35,20 @@
 #define _LIBC_sparc64_THREAD_H_
 
+#include <assert.h>
+#include <align.h>
+#include <libarch/stack.h>
+
+static inline uintptr_t arch_thread_prepare(void *stack, size_t stack_size,
+    void (*main)(void *), void *arg)
+{
+	/* We must leave space above the stack pointer for initial register spill area. */
+	uintptr_t *sp = (uintptr_t *) ALIGN_DOWN((uintptr_t) stack + stack_size - STACK_WINDOW_SAVE_AREA_SIZE - STACK_ARG_SAVE_AREA_SIZE, 16);
+
+	sp[-1] = (uintptr_t) arg;
+	sp[-2] = (uintptr_t) main;
+
+	return ((uintptr_t) sp) - STACK_BIAS;
+}
+
 #endif
 
Index: uspace/lib/c/arch/sparc64/src/thread_entry.S
===================================================================
--- uspace/lib/c/arch/sparc64/src/thread_entry.S	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/arch/sparc64/src/thread_entry.S	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -35,4 +35,6 @@
 #
 SYMBOL(__thread_entry)
+	add %sp, 0x7ff, %g1
+
 	#
 	# Create the first stack frame.
@@ -43,9 +45,12 @@
 
 	#
-	# Propagate the input arguments to the new window.
+	# Load libc entry point address and argument from stack
 	#
+	ldn [%g1 - 8], %o0
+	ldn [%g1 - 16], %g1
 
-	call __thread_main		! %o0 contains address of uarg
-	mov %i0, %o0
+	jmpl %g1, %r0
+	# Wipe link register
+	xor %o7, %o7, %o7
 
 	! not reached
Index: uspace/lib/c/generic/private/fibril.h
===================================================================
--- uspace/lib/c/generic/private/fibril.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/generic/private/fibril.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -33,5 +33,4 @@
 #include <context.h>
 #include <tls.h>
-#include <abi/proc/uarg.h>
 #include <fibril.h>
 #include <ipc/common.h>
@@ -50,5 +49,4 @@
 	context_t ctx;
 
-	uspace_arg_t uarg;
 	link_t link;
 	void *stack;
Index: uspace/lib/c/generic/private/thread.h
===================================================================
--- uspace/lib/c/generic/private/thread.h	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/generic/private/thread.h	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -37,15 +37,11 @@
 
 #include <time.h>
-#include <abi/proc/uarg.h>
 #include <libarch/thread.h>
 #include <abi/proc/thread.h>
 
 extern void __thread_entry(void);
-extern void __thread_main(uspace_arg_t *);
 
-extern errno_t thread_create(void (*)(void *), void *, const char *,
-    thread_id_t *);
+extern errno_t thread_create(errno_t (*)(void *), void *, const char *);
 extern void thread_exit(int) __attribute__((noreturn));
-extern void thread_detach(thread_id_t);
 extern thread_id_t thread_get_id(void);
 extern void thread_usleep(usec_t);
Index: uspace/lib/c/generic/thread/fibril.c
===================================================================
--- uspace/lib/c/generic/thread/fibril.c	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/generic/thread/fibril.c	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -781,7 +781,8 @@
 }
 
-static void _runner_fn(void *arg)
+static errno_t _runner_fn(void *arg)
 {
 	_helper_fibril_fn(arg);
+	return EOK;
 }
 
@@ -808,9 +809,7 @@
 
 	for (int i = 0; i < n; i++) {
-		thread_id_t tid;
-		rc = thread_create(_runner_fn, NULL, "fibril runner", &tid);
+		rc = thread_create(_runner_fn, NULL, "fibril runner");
 		if (rc != EOK)
 			return i;
-		thread_detach(tid);
 	}
 
Index: uspace/lib/c/generic/thread/thread.c
===================================================================
--- uspace/lib/c/generic/thread/thread.c	(revision 2cf8f994c2c62019d3425c8f7fcbe17e88e61a03)
+++ uspace/lib/c/generic/thread/thread.c	(revision 3fcea3438e30a096e9a5590a54508cfe3d5a697f)
@@ -37,5 +37,4 @@
 #include <stdlib.h>
 #include <libarch/faddr.h>
-#include <abi/proc/uarg.h>
 #include <fibril.h>
 #include <stack.h>
@@ -54,17 +53,17 @@
  * and exit when thread returns back.
  *
- * @param uarg Pointer to userspace argument structure.
+ * @param arg Fibril pointer.
  *
  */
-void __thread_main(uspace_arg_t *uarg)
+static void __thread_main(void *arg)
 {
+	fibril_t *fibril = arg;
+
 	assert(!__tcb_is_set());
-
-	fibril_t *fibril = uarg->uspace_thread_arg;
 	assert(fibril);
 
 	__tcb_set(fibril->tcb);
 
-	uarg->uspace_thread_function(fibril->arg);
+	fibril->func(fibril->arg);
 	/*
 	 * XXX: we cannot free the userspace stack while running on it
@@ -90,16 +89,12 @@
  * @return Zero on success or a code from @ref errno.h on failure.
  */
-errno_t thread_create(void (*function)(void *), void *arg, const char *name,
-    thread_id_t *tid)
+errno_t thread_create(errno_t (*func)(void *), void *arg, const char *name)
 {
-	uspace_arg_t *uarg = calloc(1, sizeof(uspace_arg_t));
-	if (!uarg)
+	fibril_t *fibril = fibril_alloc();
+	if (!fibril)
 		return ENOMEM;
 
-	fibril_t *fibril = fibril_alloc();
-	if (!fibril) {
-		free(uarg);
-		return ENOMEM;
-	}
+	fibril->func = func;
+	fibril->arg = arg;
 
 	size_t stack_size = stack_size_get();
@@ -109,18 +104,13 @@
 	if (stack == AS_MAP_FAILED) {
 		fibril_teardown(fibril);
-		free(uarg);
 		return ENOMEM;
 	}
 
-	fibril->arg = arg;
-	uarg->uspace_entry = (void *) FADDR(__thread_entry);
-	uarg->uspace_stack = stack;
-	uarg->uspace_stack_size = stack_size;
-	uarg->uspace_thread_function = function;
-	uarg->uspace_thread_arg = fibril;
-	uarg->uspace_uarg = uarg;
+	uintptr_t sp = arch_thread_prepare(stack, stack_size, __thread_main,
+	    fibril);
 
-	errno_t rc = (errno_t) __SYSCALL4(SYS_THREAD_CREATE, (sysarg_t) uarg,
-	    (sysarg_t) name, (sysarg_t) str_size(name), (sysarg_t) tid);
+	errno_t rc = (errno_t) __SYSCALL4(SYS_THREAD_CREATE,
+	    (sysarg_t) FADDR(__thread_entry), sp,
+	    (sysarg_t) name, (sysarg_t) str_size(name));
 
 	if (rc != EOK) {
@@ -130,5 +120,4 @@
 		 */
 		as_area_destroy(stack);
-		free(uarg);
 	}
 
@@ -148,14 +137,4 @@
 	while (true)
 		;
-}
-
-/** Detach thread.
- *
- * Currently not implemented.
- *
- * @param thread TID.
- */
-void thread_detach(thread_id_t thread)
-{
 }
 
