Index: kernel/arch/abs32le/src/userspace.c
===================================================================
--- kernel/arch/abs32le/src/userspace.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/abs32le/src/userspace.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -36,8 +36,12 @@
 #include <stdbool.h>
 #include <arch.h>
-#include <abi/proc/uarg.h>
 #include <mm/as.h>
 
-void userspace(uspace_arg_t *kernel_uarg)
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
+
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	/*
Index: kernel/arch/amd64/src/userspace.c
===================================================================
--- kernel/arch/amd64/src/userspace.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/amd64/src/userspace.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -39,6 +39,10 @@
 #include <stdint.h>
 #include <arch.h>
-#include <abi/proc/uarg.h>
 #include <mm/as.h>
+
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
 
 /** Enter userspace
@@ -47,5 +51,5 @@
  *
  */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	uint64_t rflags = read_rflags();
@@ -60,5 +64,4 @@
 	    "pushq %[utext_des]\n"
 	    "pushq %[entry]\n"
-	    "movq %[uarg], %%rax\n"
 
 	    /* %rdi is defined to hold pcb_ptr - set it to 0 */
@@ -66,11 +69,8 @@
 	    "iretq\n"
 	    :: [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
-	      [stack_top] "r" (kernel_uarg->uspace_stack +
-	      kernel_uarg->uspace_stack_size),
+	      [stack_top] "r" (sp),
 	      [rflags] "r" (rflags),
 	      [utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
-	      [entry] "r" (kernel_uarg->uspace_entry),
-	      [uarg] "r" (kernel_uarg->uspace_uarg)
-	    : "rax"
+	      [entry] "r" (pc)
 	);
 
Index: kernel/arch/arm32/src/userspace.c
===================================================================
--- kernel/arch/arm32/src/userspace.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/arm32/src/userspace.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -61,4 +61,9 @@
 } ustate_t;
 
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
+
 /** Change processor mode
  *
@@ -66,36 +71,13 @@
  *
  */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
-	volatile ustate_t ustate;
-
-	/* set first parameter */
-	ustate.r0 = kernel_uarg->uspace_uarg;
-
-	/* %r1 is defined to hold pcb_ptr - set it to 0 */
-	ustate.r1 = 0;
+	volatile ustate_t ustate = { };
 
 	/* pass the RAS page address in %r2 */
 	ustate.r2 = (uintptr_t) ras_page;
 
-	/* clear other registers */
-	ustate.r3 = 0;
-	ustate.r4 = 0;
-	ustate.r5 = 0;
-	ustate.r6 = 0;
-	ustate.r7 = 0;
-	ustate.r8 = 0;
-	ustate.r9 = 0;
-	ustate.r10 = 0;
-	ustate.r11 = 0;
-	ustate.r12 = 0;
-	ustate.lr = 0;
-
-	/* set user stack */
-	ustate.sp = kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size;
-
-	/* set where uspace execution starts */
-	ustate.pc = kernel_uarg->uspace_entry;
+	ustate.sp = sp;
+	ustate.pc = pc;
 
 	/* status register in user mode */
Index: kernel/arch/arm64/src/arm64.c
===================================================================
--- kernel/arch/arm64/src/arm64.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/arm64/src/arm64.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -146,9 +146,14 @@
 }
 
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
+
 /** Change processor mode.
  *
  * @param kernel_uarg Userspace settings (entry point, stack, ...).
  */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	/* Prepare return to EL0. */
@@ -157,9 +162,8 @@
 
 	/* Set program entry. */
-	ELR_EL1_write(kernel_uarg->uspace_entry);
+	ELR_EL1_write(pc);
 
 	/* Set user stack. */
-	SP_EL0_write(kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size);
+	SP_EL0_write(sp);
 
 	/* Clear Thread ID register. */
@@ -170,10 +174,8 @@
 	     * Reset the kernel stack to its base value.
 	     *
-	     * Clear all general-purpose registers,
-	     * except x0 that holds an argument for
-	     * the user space.
+	     * Clear all general-purpose registers.
 	     */
 	    "mov sp, %[kstack]\n"
-	    "mov x0, %[uspace_uarg]\n"
+	    "mov x0, #0\n"
 	    "mov x1, #0\n"
 	    "mov x2, #0\n"
@@ -207,6 +209,5 @@
 	    "mov x30, #0\n"
 	    "eret\n"
-	    :: [uspace_uarg] "r" (kernel_uarg->uspace_uarg),
-	      [kstack] "r" (((uint64_t) (THREAD->kstack)) +
+	    :: [kstack] "r" (((uint64_t) (THREAD->kstack)) +
 	      MEM_STACK_SIZE - SP_DELTA)
 	);
Index: kernel/arch/ia32/src/userspace.c
===================================================================
--- kernel/arch/ia32/src/userspace.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/ia32/src/userspace.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -38,8 +38,12 @@
 #include <stdint.h>
 #include <arch.h>
-#include <abi/proc/uarg.h>
 #include <mm/as.h>
 #include <arch/cpu.h>
 #include <arch/asm.h>
+
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
 
 /** Enter userspace
@@ -48,5 +52,5 @@
  *
  */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	uint32_t eflags = read_eflags();
@@ -61,5 +65,4 @@
 	    "pushl %[utext_des]\n"
 	    "pushl %[entry]\n"
-	    "movl %[uarg], %%eax\n"
 
 	    /* %edi is defined to hold pcb_ptr - set it to 0 */
@@ -70,10 +73,8 @@
 	    : [eflags_mask] "i" (~EFLAGS_NT),
 	      [udata_des] "i" (GDT_SELECTOR(UDATA_DES) | PL_USER),
-	      [stack_top] "r" (kernel_uarg->uspace_stack +
-	      kernel_uarg->uspace_stack_size),
+	      [stack_top] "r" (sp),
 	      [eflags] "r" ((eflags & ~(EFLAGS_NT)) | EFLAGS_IF),
 	      [utext_des] "i" (GDT_SELECTOR(UTEXT_DES) | PL_USER),
-	      [entry] "r" (kernel_uarg->uspace_entry),
-	      [uarg] "r" (kernel_uarg->uspace_uarg),
+	      [entry] "r" (pc),
 	      [vreg_des] "r" (GDT_SELECTOR(VREG_DES))
 	    : "eax");
Index: kernel/arch/ia64/src/ia64.c
===================================================================
--- kernel/arch/ia64/src/ia64.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/ia64/src/ia64.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -218,6 +218,11 @@
 }
 
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return ALIGN_DOWN(stack_base + stack_size / 2, STACK_ALIGNMENT);
+}
+
 /** Enter userspace and never return. */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	psr_t psr;
@@ -241,14 +246,10 @@
 	 *
 	 * When calculating stack addresses, mind the stack split between the
-	 * memory stack and the RSE stack. Each occuppies
-	 * uspace_stack_size / 2 bytes.
+	 * memory stack and the RSE stack.
+	 * Memory stack occupies area under sp, while RSE stack occupies area above.
 	 */
-	switch_to_userspace(kernel_uarg->uspace_entry,
-	    kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size / 2 -
-	    ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT),
-	    kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size / 2,
-	    kernel_uarg->uspace_uarg, psr.value, rsc.value);
+	switch_to_userspace(pc,
+	    sp, sp + ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT),
+	    0, psr.value, rsc.value);
 
 	while (true)
Index: kernel/arch/mips32/include/arch/asm.h
===================================================================
--- kernel/arch/mips32/include/arch/asm.h	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/mips32/include/arch/asm.h	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -81,5 +81,5 @@
 extern void cpu_halt(void) __attribute__((noreturn));
 extern void asm_delay_loop(uint32_t);
-extern void userspace_asm(uintptr_t, uintptr_t, uintptr_t);
+extern void userspace_asm(uintptr_t, uintptr_t);
 
 extern ipl_t interrupts_disable(void);
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/mips32/src/mips32.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -163,14 +163,16 @@
 }
 
-void userspace(uspace_arg_t *kernel_uarg)
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
+
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	/* EXL = 1, UM = 1, IE = 1 */
 	cp0_status_write(cp0_status_read() | (cp0_status_exl_exception_bit |
 	    cp0_status_um_bit | cp0_status_ie_enabled_bit));
-	cp0_epc_write(kernel_uarg->uspace_entry);
-	userspace_asm(kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size,
-	    kernel_uarg->uspace_uarg,
-	    kernel_uarg->uspace_entry);
+	cp0_epc_write(pc);
+	userspace_asm(sp, pc);
 
 	while (true)
Index: kernel/arch/mips32/src/start.S
===================================================================
--- kernel/arch/mips32/src/start.S	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/mips32/src/start.S	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -339,8 +339,7 @@
 FUNCTION_BEGIN(userspace_asm)
 	move $sp, $a0
-	move $v0, $a1
-	move $t9, $a2      /* set up correct entry into PIC code */
-	xor $a0, $a0, $a0  /* $a0 is defined to hold pcb_ptr */
-	                   /* set it to 0 */
+	xor $a0, $a0, $a0  /* $a0 is defined to hold pcb_ptr, set it to 0 */
+	xor $fp, $fp, $fp  // FIXME: wipe all userspace-accessible registers
+	xor $ra, $ra, $ra
 	eret
 FUNCTION_END(userspace_asm)
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/ppc32/src/ppc32.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -49,5 +49,4 @@
 #include <mm/km.h>
 #include <time/clock.h>
-#include <abi/proc/uarg.h>
 #include <console/console.h>
 #include <sysinfo/sysinfo.h>
@@ -290,11 +289,12 @@
 }
 
-void userspace(uspace_arg_t *kernel_uarg)
-{
-	userspace_asm(kernel_uarg->uspace_uarg,
-	    kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size - SP_DELTA,
-	    kernel_uarg->uspace_entry);
-
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size - SP_DELTA;
+}
+
+void userspace(uintptr_t pc, uintptr_t sp)
+{
+	userspace_asm(0, sp, pc);
 	unreachable();
 }
Index: kernel/arch/riscv64/src/userspace.c
===================================================================
--- kernel/arch/riscv64/src/userspace.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/riscv64/src/userspace.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -33,8 +33,12 @@
  */
 
-#include <abi/proc/uarg.h>
 #include <userspace.h>
 
-void userspace(uspace_arg_t *kernel_uarg)
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return stack_base + stack_size;
+}
+
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	// FIXME
Index: kernel/arch/sparc64/src/sun4u/asm.S
===================================================================
--- kernel/arch/sparc64/src/sun4u/asm.S	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/sparc64/src/sun4u/asm.S	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -83,5 +83,5 @@
  */
 FUNCTION_BEGIN(switch_to_userspace)
-	save %o1, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
+	save %o1, 0, %sp
 	flushw
 	wrpr %g0, 0, %cleanwin		! avoid information leak
Index: kernel/arch/sparc64/src/sun4u/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4u/sparc64.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/sparc64/src/sun4u/sparc64.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -159,13 +159,14 @@
 }
 
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return ALIGN_DOWN(stack_base + stack_size - STACK_WINDOW_SAVE_AREA_SIZE - STACK_ARG_SAVE_AREA_SIZE, 16) - STACK_BIAS;
+}
+
 /** Switch to userspace. */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	(void) interrupts_disable();
-	switch_to_userspace(kernel_uarg->uspace_entry,
-	    kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size -
-	    (ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT) + STACK_BIAS),
-	    kernel_uarg->uspace_uarg);
+	switch_to_userspace(pc, sp, 0);
 
 	/* Not reached */
Index: kernel/arch/sparc64/src/sun4v/asm.S
===================================================================
--- kernel/arch/sparc64/src/sun4v/asm.S	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/sparc64/src/sun4v/asm.S	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -41,5 +41,5 @@
  */
 FUNCTION_BEGIN(switch_to_userspace)
-	save %o1, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
+	save %o1, 0, %sp
 	flushw
 	wrpr %g0, 0, %cleanwin		! avoid information leak
Index: kernel/arch/sparc64/src/sun4v/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4v/sparc64.c	(revision 3526f4f3e57bcdc0f37d47d89769e3bdd0c9e9c4)
+++ kernel/arch/sparc64/src/sun4v/sparc64.c	(revision d31c3ea70b393289736cdac0e91fa5c5eba06c4c)
@@ -157,13 +157,14 @@
 }
 
+uintptr_t arch_get_initial_sp(uintptr_t stack_base, uintptr_t stack_size)
+{
+	return ALIGN_DOWN(stack_base + stack_size - STACK_WINDOW_SAVE_AREA_SIZE - STACK_ARG_SAVE_AREA_SIZE, 16) - STACK_BIAS;
+}
+
 /** Switch to userspace. */
-void userspace(uspace_arg_t *kernel_uarg)
+void userspace(uintptr_t pc, uintptr_t sp)
 {
 	(void) interrupts_disable();
-	switch_to_userspace(kernel_uarg->uspace_entry,
-	    kernel_uarg->uspace_stack +
-	    kernel_uarg->uspace_stack_size -
-	    (ALIGN_UP(STACK_ITEM_SIZE, STACK_ALIGNMENT) + STACK_BIAS),
-	    kernel_uarg->uspace_uarg);
+	switch_to_userspace(pc, sp, 0);
 
 	/* Not reached */
