summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel/process_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/process_64.c')
-rw-r--r--arch/sparc/kernel/process_64.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 529adfecd58c..e889da8e4835 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -564,17 +564,19 @@ barf:
* under SunOS are nothing short of bletcherous:
* Parent --> %o0 == childs pid, %o1 == 0
* Child --> %o0 == parents pid, %o1 == 1
+ *
+ * clone3() - Uses regular kernel return value conventions
*/
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
- unsigned long clone_flags = args->flags;
- unsigned long sp = args->stack;
+ u64 clone_flags = args->flags;
unsigned long tls = args->tls;
struct thread_info *t = task_thread_info(p);
struct pt_regs *regs = current_pt_regs();
struct sparc_stackf *parent_sf;
unsigned long child_stack_sz;
char *child_trap_frame;
+ unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
/* Calculate offset to stack_frame & pt_regs */
child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
@@ -616,12 +618,25 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
if (t->utraps)
t->utraps[0]++;
- /* Set the return value for the child. */
- t->kregs->u_regs[UREG_I0] = current->pid;
- t->kregs->u_regs[UREG_I1] = 1;
+ /* Handle return value conventions */
+ if (regs->u_regs[UREG_G1] == __NR_clone3) {
+ /* clone3() - use regular kernel return value convention */
+
+ /* Set the return value for the child. */
+ t->kregs->u_regs[UREG_I0] = 0;
+
+ /* Clear g1 to indicate user thread */
+ t->kregs->u_regs[UREG_G1] = 0;
+ } else {
+ /* clone()/fork() - use SunOS return value convention */
+
+ /* Set the return value for the child. */
+ t->kregs->u_regs[UREG_I0] = current->pid;
+ t->kregs->u_regs[UREG_I1] = 1;
- /* Set the second return value for the parent. */
- regs->u_regs[UREG_I1] = 0;
+ /* Set the second return value for the parent. */
+ regs->u_regs[UREG_I1] = 0;
+ }
if (clone_flags & CLONE_SETTLS)
t->kregs->u_regs[UREG_G7] = tls;