1 /* $Id: process.c,v 1.147 2000/05/09 17:40:13 davem Exp $
2 * linux/arch/sparc/kernel/process.c
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
9 * This file handles the architecture-dependent parts of process handling..
12 #define __KERNEL_SYSCALLS__
15 #include <linux/errno.h>
16 #include <linux/sched.h>
17 #include <linux/kernel.h>
19 #include <linux/stddef.h>
20 #include <linux/unistd.h>
21 #include <linux/ptrace.h>
22 #include <linux/malloc.h>
23 #include <linux/user.h>
24 #include <linux/a.out.h>
25 #include <linux/config.h>
26 #include <linux/smp.h>
27 #include <linux/smp_lock.h>
28 #include <linux/reboot.h>
29 #include <linux/delay.h>
31 #include <asm/auxio.h>
32 #include <asm/oplib.h>
33 #include <asm/uaccess.h>
34 #include <asm/system.h>
36 #include <asm/pgalloc.h>
37 #include <asm/pgtable.h>
38 #include <asm/delay.h>
39 #include <asm/processor.h>
43 extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
45 struct task_struct
*last_task_used_math
= NULL
;
46 struct task_struct
*current_set
[NR_CPUS
] = {&init_task
, };
50 #define SUN4C_FAULT_HIGH 100
53 * the idle loop on a Sparc... ;)
59 if (current
->pid
!= 0)
62 /* endless idle loop with no priority at all */
63 current
->priority
= 0;
64 current
->counter
= -100;
68 if (ARCH_SUN4C_SUN4
) {
69 static int count
= HZ
;
70 static unsigned long last_jiffies
= 0;
71 static unsigned long last_faults
= 0;
72 static unsigned long fps
= 0;
77 extern unsigned long sun4c_kernel_faults
;
78 extern void sun4c_grow_kernel_ring(void);
82 count
-= (now
- last_jiffies
);
86 faults
= sun4c_kernel_faults
;
87 fps
= (fps
+ (faults
- last_faults
)) >> 1;
90 printk("kernel faults / second = %d\n", fps
);
92 if (fps
>= SUN4C_FAULT_HIGH
) {
93 sun4c_grow_kernel_ring();
108 /* This is being executed in task 0 'user space'. */
111 /* endless idle loop with no priority at all */
112 current
->priority
= 0;
113 current
->counter
= -100;
117 if(current
->need_resched
) {
121 barrier(); /* or else gcc optimizes... */
127 extern char reboot_command
[];
129 #ifdef CONFIG_SUN_CONSOLE
130 extern void (*prom_palette
)(int);
131 extern int serial_console
;
134 void machine_halt(void)
139 #ifdef CONFIG_SUN_CONSOLE
140 if (!serial_console
&& prom_palette
)
144 panic("Halt failed!");
147 void machine_restart(char * cmd
)
155 p
= strchr (reboot_command
, '\n');
157 #ifdef CONFIG_SUN_CONSOLE
158 if (!serial_console
&& prom_palette
)
164 prom_reboot(reboot_command
);
165 prom_feval ("reset");
166 panic("Reboot failed!");
169 void machine_power_off(void)
171 #ifdef CONFIG_SUN_AUXIO
172 if (auxio_power_register
)
173 *auxio_power_register
|= AUXIO_POWER_OFF
;
178 void show_regwindow(struct reg_window
*rw
)
180 printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
181 "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
182 rw
->locals
[0], rw
->locals
[1], rw
->locals
[2], rw
->locals
[3],
183 rw
->locals
[4], rw
->locals
[5], rw
->locals
[6], rw
->locals
[7]);
184 printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
185 "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
186 rw
->ins
[0], rw
->ins
[1], rw
->ins
[2], rw
->ins
[3],
187 rw
->ins
[4], rw
->ins
[5], rw
->ins
[6], rw
->ins
[7]);
190 static spinlock_t sparc_backtrace_lock
= SPIN_LOCK_UNLOCKED
;
192 void __show_backtrace(unsigned long fp
)
194 struct reg_window
*rw
;
196 int cpu
= smp_processor_id();
198 spin_lock_irqsave(&sparc_backtrace_lock
, flags
);
200 rw
= (struct reg_window
*)fp
;
201 while(rw
&& (((unsigned long) rw
) >= PAGE_OFFSET
) &&
202 !(((unsigned long) rw
) & 0x7)) {
203 printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
204 "FP[%08lx] CALLER[%08lx]\n", cpu
,
205 rw
->ins
[0], rw
->ins
[1], rw
->ins
[2], rw
->ins
[3],
206 rw
->ins
[4], rw
->ins
[5],
209 rw
= (struct reg_window
*) rw
->ins
[6];
211 spin_unlock_irqrestore(&sparc_backtrace_lock
, flags
);
214 #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
215 #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
216 #define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))
218 void show_backtrace(void)
222 __SAVE
; __SAVE
; __SAVE
; __SAVE
;
223 __SAVE
; __SAVE
; __SAVE
; __SAVE
;
224 __RESTORE
; __RESTORE
; __RESTORE
; __RESTORE
;
225 __RESTORE
; __RESTORE
; __RESTORE
; __RESTORE
;
229 __show_backtrace(fp
);
233 void smp_show_backtrace_all_cpus(void)
235 xc0((smpfunc_t
) show_backtrace
);
239 void show_stackframe(struct sparc_stackf
*sf
)
245 printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
246 "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
247 sf
->locals
[0], sf
->locals
[1], sf
->locals
[2], sf
->locals
[3],
248 sf
->locals
[4], sf
->locals
[5], sf
->locals
[6], sf
->locals
[7]);
249 printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
250 "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
251 sf
->ins
[0], sf
->ins
[1], sf
->ins
[2], sf
->ins
[3],
252 sf
->ins
[4], sf
->ins
[5], (unsigned long)sf
->fp
, sf
->callers_pc
);
253 printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx "
254 "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n",
255 (unsigned long)sf
->structptr
, sf
->xargs
[0], sf
->xargs
[1],
256 sf
->xargs
[2], sf
->xargs
[3], sf
->xargs
[4], sf
->xargs
[5],
258 size
= ((unsigned long)sf
->fp
) - ((unsigned long)sf
);
259 size
-= STACKFRAME_SZ
;
260 stk
= (unsigned long *)((unsigned long)sf
+ STACKFRAME_SZ
);
263 printk("s%d: %08lx\n", i
++, *stk
++);
264 } while ((size
-= sizeof(unsigned long)));
267 void show_regs(struct pt_regs
* regs
)
269 printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs
->psr
,
270 regs
->pc
, regs
->npc
, regs
->y
);
271 printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ",
272 regs
->u_regs
[0], regs
->u_regs
[1], regs
->u_regs
[2],
274 printk("g4: %08lx g5: %08lx g6: %08lx g7: %08lx\n",
275 regs
->u_regs
[4], regs
->u_regs
[5], regs
->u_regs
[6],
277 printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx ",
278 regs
->u_regs
[8], regs
->u_regs
[9], regs
->u_regs
[10],
280 printk("o4: %08lx o5: %08lx sp: %08lx o7: %08lx\n",
281 regs
->u_regs
[12], regs
->u_regs
[13], regs
->u_regs
[14],
283 show_regwindow((struct reg_window
*)regs
->u_regs
[14]);
287 void show_thread(struct thread_struct
*thread
)
291 printk("uwinmask: 0x%08lx kregs: 0x%08lx\n", thread
->uwinmask
, (unsigned long)thread
->kregs
);
292 show_regs(thread
->kregs
);
293 printk("ksp: 0x%08lx kpc: 0x%08lx\n", thread
->ksp
, thread
->kpc
);
294 printk("kpsr: 0x%08lx kwim: 0x%08lx\n", thread
->kpsr
, thread
->kwim
);
295 printk("fork_kpsr: 0x%08lx fork_kwim: 0x%08lx\n", thread
->fork_kpsr
, thread
->fork_kwim
);
297 for (i
= 0; i
< NSWINS
; i
++) {
298 if (!thread
->rwbuf_stkptrs
[i
])
300 printk("reg_window[%d]:\n", i
);
301 printk("stack ptr: 0x%08lx\n", thread
->rwbuf_stkptrs
[i
]);
302 show_regwindow(&thread
->reg_window
[i
]);
304 printk("w_saved: 0x%08lx\n", thread
->w_saved
);
306 /* XXX missing: float_regs */
307 printk("fsr: 0x%08lx fpqdepth: 0x%08lx\n", thread
->fsr
, thread
->fpqdepth
);
308 /* XXX missing: fpqueue */
310 printk("flags: 0x%08lx current_ds: 0x%08lx\n", thread
->flags
, thread
->current_ds
.seg
);
312 show_regwindow((struct reg_window
*)thread
->ksp
);
314 /* XXX missing: core_exec */
319 * Free current thread data structures etc..
321 void exit_thread(void)
324 if(last_task_used_math
== current
) {
326 if(current
->flags
& PF_USEDFPU
) {
328 /* Keep process from leaving FPU in a bogon state. */
329 put_psr(get_psr() | PSR_EF
);
330 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
331 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
333 last_task_used_math
= NULL
;
335 current
->flags
&= ~PF_USEDFPU
;
340 void flush_thread(void)
342 current
->thread
.w_saved
= 0;
344 /* No new signal delivery by default */
345 current
->thread
.new_signal
= 0;
347 if(last_task_used_math
== current
) {
349 if(current
->flags
& PF_USEDFPU
) {
352 put_psr(get_psr() | PSR_EF
);
353 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
354 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
356 last_task_used_math
= NULL
;
358 current
->flags
&= ~PF_USEDFPU
;
362 /* Now, this task is no longer a kernel thread. */
363 current
->thread
.current_ds
= USER_DS
;
364 if (current
->thread
.flags
& SPARC_FLAG_KTHREAD
) {
365 current
->thread
.flags
&= ~SPARC_FLAG_KTHREAD
;
367 /* We must fixup kregs as well. */
368 current
->thread
.kregs
= (struct pt_regs
*)
369 (((unsigned long)current
) +
370 (TASK_UNION_SIZE
- TRACEREG_SZ
));
374 static __inline__
void copy_regs(struct pt_regs
*dst
, struct pt_regs
*src
)
376 __asm__
__volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
377 "ldd\t[%1 + 0x08], %%g4\n\t"
378 "ldd\t[%1 + 0x10], %%o4\n\t"
379 "std\t%%g2, [%0 + 0x00]\n\t"
380 "std\t%%g4, [%0 + 0x08]\n\t"
381 "std\t%%o4, [%0 + 0x10]\n\t"
382 "ldd\t[%1 + 0x18], %%g2\n\t"
383 "ldd\t[%1 + 0x20], %%g4\n\t"
384 "ldd\t[%1 + 0x28], %%o4\n\t"
385 "std\t%%g2, [%0 + 0x18]\n\t"
386 "std\t%%g4, [%0 + 0x20]\n\t"
387 "std\t%%o4, [%0 + 0x28]\n\t"
388 "ldd\t[%1 + 0x30], %%g2\n\t"
389 "ldd\t[%1 + 0x38], %%g4\n\t"
390 "ldd\t[%1 + 0x40], %%o4\n\t"
391 "std\t%%g2, [%0 + 0x30]\n\t"
392 "std\t%%g4, [%0 + 0x38]\n\t"
393 "ldd\t[%1 + 0x48], %%g2\n\t"
394 "std\t%%o4, [%0 + 0x40]\n\t"
395 "std\t%%g2, [%0 + 0x48]\n\t" : :
396 "r" (dst
), "r" (src
) :
397 "g2", "g3", "g4", "g5", "o4", "o5");
400 static __inline__
void copy_regwin(struct reg_window
*dst
, struct reg_window
*src
)
402 __asm__
__volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
403 "ldd\t[%1 + 0x08], %%g4\n\t"
404 "ldd\t[%1 + 0x10], %%o4\n\t"
405 "std\t%%g2, [%0 + 0x00]\n\t"
406 "std\t%%g4, [%0 + 0x08]\n\t"
407 "std\t%%o4, [%0 + 0x10]\n\t"
408 "ldd\t[%1 + 0x18], %%g2\n\t"
409 "ldd\t[%1 + 0x20], %%g4\n\t"
410 "ldd\t[%1 + 0x28], %%o4\n\t"
411 "std\t%%g2, [%0 + 0x18]\n\t"
412 "std\t%%g4, [%0 + 0x20]\n\t"
413 "std\t%%o4, [%0 + 0x28]\n\t"
414 "ldd\t[%1 + 0x30], %%g2\n\t"
415 "ldd\t[%1 + 0x38], %%g4\n\t"
416 "std\t%%g2, [%0 + 0x30]\n\t"
417 "std\t%%g4, [%0 + 0x38]\n\t" : :
418 "r" (dst
), "r" (src
) :
419 "g2", "g3", "g4", "g5", "o4", "o5");
422 static __inline__
struct sparc_stackf
*
423 clone_stackframe(struct sparc_stackf
*dst
, struct sparc_stackf
*src
)
426 struct sparc_stackf
*sp
;
428 size
= ((unsigned long)src
->fp
) - ((unsigned long)src
);
429 sp
= (struct sparc_stackf
*)(((unsigned long)dst
) - size
);
431 /* do_fork() grabs the parent semaphore, we must release it
432 * temporarily so we can build the child clone stack frame
433 * without deadlocking.
435 if (copy_to_user(sp
, src
, size
))
436 sp
= (struct sparc_stackf
*) 0;
437 else if (put_user(dst
, &sp
->fp
))
438 sp
= (struct sparc_stackf
*) 0;
444 /* Copy a Sparc thread. The fork() return value conventions
445 * under SunOS are nothing short of bletcherous:
446 * Parent --> %o0 == childs pid, %o1 == 0
447 * Child --> %o0 == parents pid, %o1 == 1
449 * NOTE: We have a separate fork kpsr/kwim because
450 * the parent could change these values between
451 * sys_fork invocation and when we reach here
452 * if the parent should sleep while trying to
453 * allocate the task_struct and kernel stack in
457 extern void ret_from_smpfork(void);
459 extern void ret_from_syscall(void);
462 int copy_thread(int nr
, unsigned long clone_flags
, unsigned long sp
,
463 struct task_struct
*p
, struct pt_regs
*regs
)
465 struct pt_regs
*childregs
;
466 struct reg_window
*new_stack
;
467 unsigned long stack_offset
;
470 if(last_task_used_math
== current
) {
472 if(current
->flags
& PF_USEDFPU
) {
474 put_psr(get_psr() | PSR_EF
);
475 fpsave(&p
->thread
.float_regs
[0], &p
->thread
.fsr
,
476 &p
->thread
.fpqueue
[0], &p
->thread
.fpqdepth
);
478 current
->flags
&= ~PF_USEDFPU
;
482 /* Calculate offset to stack_frame & pt_regs */
483 stack_offset
= TASK_UNION_SIZE
- TRACEREG_SZ
;
485 if(regs
->psr
& PSR_PS
)
486 stack_offset
-= REGWIN_SZ
;
487 childregs
= ((struct pt_regs
*) (((unsigned long)p
) + stack_offset
));
488 copy_regs(childregs
, regs
);
489 new_stack
= (((struct reg_window
*) childregs
) - 1);
490 copy_regwin(new_stack
, (((struct reg_window
*) regs
) - 1));
492 p
->thread
.ksp
= (unsigned long) new_stack
;
494 p
->thread
.kpc
= (((unsigned long) ret_from_smpfork
) - 0x8);
495 p
->thread
.kpsr
= current
->thread
.fork_kpsr
| PSR_PIL
;
497 p
->thread
.kpc
= (((unsigned long) ret_from_syscall
) - 0x8);
498 p
->thread
.kpsr
= current
->thread
.fork_kpsr
;
500 p
->thread
.kwim
= current
->thread
.fork_kwim
;
502 /* This is used for sun4c only */
503 atomic_set(&p
->thread
.refcount
, 1);
505 if(regs
->psr
& PSR_PS
) {
506 extern struct pt_regs fake_swapper_regs
;
508 p
->thread
.kregs
= &fake_swapper_regs
;
509 new_stack
= (struct reg_window
*)
510 ((((unsigned long)p
) +
513 childregs
->u_regs
[UREG_FP
] = (unsigned long) new_stack
;
514 p
->thread
.flags
|= SPARC_FLAG_KTHREAD
;
515 p
->thread
.current_ds
= KERNEL_DS
;
516 memcpy((void *)new_stack
,
517 (void *)regs
->u_regs
[UREG_FP
],
518 sizeof(struct reg_window
));
519 childregs
->u_regs
[UREG_G6
] = (unsigned long) p
;
521 p
->thread
.kregs
= childregs
;
522 childregs
->u_regs
[UREG_FP
] = sp
;
523 p
->thread
.flags
&= ~SPARC_FLAG_KTHREAD
;
524 p
->thread
.current_ds
= USER_DS
;
526 if (sp
!= regs
->u_regs
[UREG_FP
]) {
527 struct sparc_stackf
*childstack
;
528 struct sparc_stackf
*parentstack
;
531 * This is a clone() call with supplied user stack.
532 * Set some valid stack frames to give to the child.
534 childstack
= (struct sparc_stackf
*) (sp
& ~0x7UL
);
535 parentstack
= (struct sparc_stackf
*) regs
->u_regs
[UREG_FP
];
538 printk("clone: parent stack:\n");
539 show_stackframe(parentstack
);
542 childstack
= clone_stackframe(childstack
, parentstack
);
547 printk("clone: child stack:\n");
548 show_stackframe(childstack
);
551 childregs
->u_regs
[UREG_FP
] = (unsigned long)childstack
;
555 /* Set the return value for the child. */
556 childregs
->u_regs
[UREG_I0
] = current
->pid
;
557 childregs
->u_regs
[UREG_I1
] = 1;
559 /* Set the return value for the parent. */
560 regs
->u_regs
[UREG_I1
] = 0;
566 * fill in the user structure for a core dump..
568 void dump_thread(struct pt_regs
* regs
, struct user
* dump
)
570 unsigned long first_stack_page
;
572 dump
->magic
= SUNOS_CORE_MAGIC
;
573 dump
->len
= sizeof(struct user
);
574 dump
->regs
.psr
= regs
->psr
;
575 dump
->regs
.pc
= regs
->pc
;
576 dump
->regs
.npc
= regs
->npc
;
577 dump
->regs
.y
= regs
->y
;
579 memcpy(&dump
->regs
.regs
[0], ®s
->u_regs
[1], (sizeof(unsigned long) * 15));
580 dump
->uexec
= current
->thread
.core_exec
;
581 dump
->u_tsize
= (((unsigned long) current
->mm
->end_code
) -
582 ((unsigned long) current
->mm
->start_code
)) & ~(PAGE_SIZE
- 1);
583 dump
->u_dsize
= ((unsigned long) (current
->mm
->brk
+ (PAGE_SIZE
-1)));
584 dump
->u_dsize
-= dump
->u_tsize
;
585 dump
->u_dsize
&= ~(PAGE_SIZE
- 1);
586 first_stack_page
= (regs
->u_regs
[UREG_FP
] & ~(PAGE_SIZE
- 1));
587 dump
->u_ssize
= (TASK_SIZE
- first_stack_page
) & ~(PAGE_SIZE
- 1);
588 memcpy(&dump
->fpu
.fpstatus
.fregs
.regs
[0], ¤t
->thread
.float_regs
[0], (sizeof(unsigned long) * 32));
589 dump
->fpu
.fpstatus
.fsr
= current
->thread
.fsr
;
590 dump
->fpu
.fpstatus
.flags
= dump
->fpu
.fpstatus
.extra
= 0;
591 dump
->fpu
.fpstatus
.fpq_count
= current
->thread
.fpqdepth
;
592 memcpy(&dump
->fpu
.fpstatus
.fpq
[0], ¤t
->thread
.fpqueue
[0],
593 ((sizeof(unsigned long) * 2) * 16));
598 * fill in the fpu structure for a core dump.
600 int dump_fpu (struct pt_regs
* regs
, elf_fpregset_t
* fpregs
)
602 if (current
->used_math
== 0) {
603 memset(fpregs
, 0, sizeof(*fpregs
));
604 fpregs
->pr_q_entrysize
= 8;
608 if (current
->flags
& PF_USEDFPU
) {
609 put_psr(get_psr() | PSR_EF
);
610 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
611 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
612 regs
->psr
&= ~(PSR_EF
);
613 current
->flags
&= ~(PF_USEDFPU
);
616 if (current
== last_task_used_math
) {
617 put_psr(get_psr() | PSR_EF
);
618 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
619 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
620 last_task_used_math
= 0;
621 regs
->psr
&= ~(PSR_EF
);
624 memcpy(&fpregs
->pr_fr
.pr_regs
[0],
625 ¤t
->thread
.float_regs
[0],
626 (sizeof(unsigned long) * 32));
627 fpregs
->pr_fsr
= current
->thread
.fsr
;
628 fpregs
->pr_qcnt
= current
->thread
.fpqdepth
;
629 fpregs
->pr_q_entrysize
= 8;
631 if(fpregs
->pr_qcnt
!= 0) {
632 memcpy(&fpregs
->pr_q
[0],
633 ¤t
->thread
.fpqueue
[0],
634 sizeof(struct fpq
) * fpregs
->pr_qcnt
);
636 /* Zero out the rest. */
637 memset(&fpregs
->pr_q
[fpregs
->pr_qcnt
], 0,
638 sizeof(struct fpq
) * (32 - fpregs
->pr_qcnt
));
643 * sparc_execve() executes a new program after the asm stub has set
644 * things up for us. This should basically do what I want it to.
646 asmlinkage
int sparc_execve(struct pt_regs
*regs
)
651 /* Check for indirect call. */
652 if(regs
->u_regs
[UREG_G1
] == 0)
655 filename
= getname((char *)regs
->u_regs
[base
+ UREG_I0
]);
656 error
= PTR_ERR(filename
);
659 error
= do_execve(filename
, (char **) regs
->u_regs
[base
+ UREG_I1
],
660 (char **) regs
->u_regs
[base
+ UREG_I2
], regs
);
667 * This is the mechanism for creating a new kernel thread.
669 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
670 * who haven't done an "execve()") should use this: it will work within
671 * a system call from a "real" process, but the process memory space will
672 * not be free'd until both the parent and the child have exited.
674 pid_t
kernel_thread(int (*fn
)(void *), void * arg
, unsigned long flags
)
678 __asm__
__volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */
679 "mov %5, %%g3\n\t" /* and arg. */
681 "mov %2, %%o0\n\t" /* Clone flags. */
682 "mov 0, %%o1\n\t" /* usp arg == 0 */
683 "t 0x10\n\t" /* Linux/Sparc clone(). */
685 "be 1f\n\t" /* The parent, just return. */
686 " nop\n\t" /* Delay slot. */
687 "jmpl %%g2, %%o7\n\t" /* Call the function. */
688 " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
690 "t 0x10\n\t" /* Linux/Sparc exit(). */
691 /* Notreached by child. */
692 "1: mov %%o0, %0\n\t" :
694 "i" (__NR_clone
), "r" (flags
| CLONE_VM
),
695 "i" (__NR_exit
), "r" (fn
), "r" (arg
) :
696 "g1", "g2", "g3", "o0", "o1", "memory", "cc");