1 /* $Id: process.c,v 1.150 2000/07/11 18:49:22 anton 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 */
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 */
113 current
->counter
= -100;
117 if(current
->need_resched
) {
121 barrier(); /* or else gcc optimizes... */
127 extern char reboot_command
[];
129 extern int serial_console
;
131 #ifdef CONFIG_SUN_CONSOLE
132 extern void (*prom_palette
)(int);
135 void machine_halt(void)
140 #ifdef CONFIG_SUN_CONSOLE
141 if (!serial_console
&& prom_palette
)
145 panic("Halt failed!");
148 void machine_restart(char * cmd
)
156 p
= strchr (reboot_command
, '\n');
158 #ifdef CONFIG_SUN_CONSOLE
159 if (!serial_console
&& prom_palette
)
165 prom_reboot(reboot_command
);
166 prom_feval ("reset");
167 panic("Reboot failed!");
170 void machine_power_off(void)
172 #ifdef CONFIG_SUN_AUXIO
173 if (auxio_power_register
&& !serial_console
)
174 *auxio_power_register
|= AUXIO_POWER_OFF
;
179 void show_regwindow(struct reg_window
*rw
)
181 printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
182 "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
183 rw
->locals
[0], rw
->locals
[1], rw
->locals
[2], rw
->locals
[3],
184 rw
->locals
[4], rw
->locals
[5], rw
->locals
[6], rw
->locals
[7]);
185 printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
186 "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
187 rw
->ins
[0], rw
->ins
[1], rw
->ins
[2], rw
->ins
[3],
188 rw
->ins
[4], rw
->ins
[5], rw
->ins
[6], rw
->ins
[7]);
191 static spinlock_t sparc_backtrace_lock
= SPIN_LOCK_UNLOCKED
;
193 void __show_backtrace(unsigned long fp
)
195 struct reg_window
*rw
;
197 int cpu
= smp_processor_id();
199 spin_lock_irqsave(&sparc_backtrace_lock
, flags
);
201 rw
= (struct reg_window
*)fp
;
202 while(rw
&& (((unsigned long) rw
) >= PAGE_OFFSET
) &&
203 !(((unsigned long) rw
) & 0x7)) {
204 printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
205 "FP[%08lx] CALLER[%08lx]\n", cpu
,
206 rw
->ins
[0], rw
->ins
[1], rw
->ins
[2], rw
->ins
[3],
207 rw
->ins
[4], rw
->ins
[5],
210 rw
= (struct reg_window
*) rw
->ins
[6];
212 spin_unlock_irqrestore(&sparc_backtrace_lock
, flags
);
215 #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
216 #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
217 #define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))
219 void show_backtrace(void)
223 __SAVE
; __SAVE
; __SAVE
; __SAVE
;
224 __SAVE
; __SAVE
; __SAVE
; __SAVE
;
225 __RESTORE
; __RESTORE
; __RESTORE
; __RESTORE
;
226 __RESTORE
; __RESTORE
; __RESTORE
; __RESTORE
;
230 __show_backtrace(fp
);
234 void smp_show_backtrace_all_cpus(void)
236 xc0((smpfunc_t
) show_backtrace
);
241 void show_stackframe(struct sparc_stackf
*sf
)
247 printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
248 "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
249 sf
->locals
[0], sf
->locals
[1], sf
->locals
[2], sf
->locals
[3],
250 sf
->locals
[4], sf
->locals
[5], sf
->locals
[6], sf
->locals
[7]);
251 printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
252 "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
253 sf
->ins
[0], sf
->ins
[1], sf
->ins
[2], sf
->ins
[3],
254 sf
->ins
[4], sf
->ins
[5], (unsigned long)sf
->fp
, sf
->callers_pc
);
255 printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx "
256 "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n",
257 (unsigned long)sf
->structptr
, sf
->xargs
[0], sf
->xargs
[1],
258 sf
->xargs
[2], sf
->xargs
[3], sf
->xargs
[4], sf
->xargs
[5],
260 size
= ((unsigned long)sf
->fp
) - ((unsigned long)sf
);
261 size
-= STACKFRAME_SZ
;
262 stk
= (unsigned long *)((unsigned long)sf
+ STACKFRAME_SZ
);
265 printk("s%d: %08lx\n", i
++, *stk
++);
266 } while ((size
-= sizeof(unsigned long)));
269 void show_regs(struct pt_regs
* regs
)
271 printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs
->psr
,
272 regs
->pc
, regs
->npc
, regs
->y
);
273 printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ",
274 regs
->u_regs
[0], regs
->u_regs
[1], regs
->u_regs
[2],
276 printk("g4: %08lx g5: %08lx g6: %08lx g7: %08lx\n",
277 regs
->u_regs
[4], regs
->u_regs
[5], regs
->u_regs
[6],
279 printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx ",
280 regs
->u_regs
[8], regs
->u_regs
[9], regs
->u_regs
[10],
282 printk("o4: %08lx o5: %08lx sp: %08lx o7: %08lx\n",
283 regs
->u_regs
[12], regs
->u_regs
[13], regs
->u_regs
[14],
285 show_regwindow((struct reg_window
*)regs
->u_regs
[14]);
289 void show_thread(struct thread_struct
*thread
)
293 printk("uwinmask: 0x%08lx kregs: 0x%08lx\n", thread
->uwinmask
, (unsigned long)thread
->kregs
);
294 show_regs(thread
->kregs
);
295 printk("ksp: 0x%08lx kpc: 0x%08lx\n", thread
->ksp
, thread
->kpc
);
296 printk("kpsr: 0x%08lx kwim: 0x%08lx\n", thread
->kpsr
, thread
->kwim
);
297 printk("fork_kpsr: 0x%08lx fork_kwim: 0x%08lx\n", thread
->fork_kpsr
, thread
->fork_kwim
);
299 for (i
= 0; i
< NSWINS
; i
++) {
300 if (!thread
->rwbuf_stkptrs
[i
])
302 printk("reg_window[%d]:\n", i
);
303 printk("stack ptr: 0x%08lx\n", thread
->rwbuf_stkptrs
[i
]);
304 show_regwindow(&thread
->reg_window
[i
]);
306 printk("w_saved: 0x%08lx\n", thread
->w_saved
);
308 /* XXX missing: float_regs */
309 printk("fsr: 0x%08lx fpqdepth: 0x%08lx\n", thread
->fsr
, thread
->fpqdepth
);
310 /* XXX missing: fpqueue */
312 printk("flags: 0x%08lx current_ds: 0x%08lx\n", thread
->flags
, thread
->current_ds
.seg
);
314 show_regwindow((struct reg_window
*)thread
->ksp
);
316 /* XXX missing: core_exec */
321 * Free current thread data structures etc..
323 void exit_thread(void)
326 if(last_task_used_math
== current
) {
328 if(current
->flags
& PF_USEDFPU
) {
330 /* Keep process from leaving FPU in a bogon state. */
331 put_psr(get_psr() | PSR_EF
);
332 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
333 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
335 last_task_used_math
= NULL
;
337 current
->flags
&= ~PF_USEDFPU
;
342 void flush_thread(void)
344 current
->thread
.w_saved
= 0;
346 /* No new signal delivery by default */
347 current
->thread
.new_signal
= 0;
349 if(last_task_used_math
== current
) {
351 if(current
->flags
& PF_USEDFPU
) {
354 put_psr(get_psr() | PSR_EF
);
355 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
356 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
358 last_task_used_math
= NULL
;
360 current
->flags
&= ~PF_USEDFPU
;
364 /* Now, this task is no longer a kernel thread. */
365 current
->thread
.current_ds
= USER_DS
;
366 if (current
->thread
.flags
& SPARC_FLAG_KTHREAD
) {
367 current
->thread
.flags
&= ~SPARC_FLAG_KTHREAD
;
369 /* We must fixup kregs as well. */
370 current
->thread
.kregs
= (struct pt_regs
*)
371 (((unsigned long)current
) +
372 (TASK_UNION_SIZE
- TRACEREG_SZ
));
376 static __inline__
void copy_regs(struct pt_regs
*dst
, struct pt_regs
*src
)
378 __asm__
__volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
379 "ldd\t[%1 + 0x08], %%g4\n\t"
380 "ldd\t[%1 + 0x10], %%o4\n\t"
381 "std\t%%g2, [%0 + 0x00]\n\t"
382 "std\t%%g4, [%0 + 0x08]\n\t"
383 "std\t%%o4, [%0 + 0x10]\n\t"
384 "ldd\t[%1 + 0x18], %%g2\n\t"
385 "ldd\t[%1 + 0x20], %%g4\n\t"
386 "ldd\t[%1 + 0x28], %%o4\n\t"
387 "std\t%%g2, [%0 + 0x18]\n\t"
388 "std\t%%g4, [%0 + 0x20]\n\t"
389 "std\t%%o4, [%0 + 0x28]\n\t"
390 "ldd\t[%1 + 0x30], %%g2\n\t"
391 "ldd\t[%1 + 0x38], %%g4\n\t"
392 "ldd\t[%1 + 0x40], %%o4\n\t"
393 "std\t%%g2, [%0 + 0x30]\n\t"
394 "std\t%%g4, [%0 + 0x38]\n\t"
395 "ldd\t[%1 + 0x48], %%g2\n\t"
396 "std\t%%o4, [%0 + 0x40]\n\t"
397 "std\t%%g2, [%0 + 0x48]\n\t" : :
398 "r" (dst
), "r" (src
) :
399 "g2", "g3", "g4", "g5", "o4", "o5");
402 static __inline__
void copy_regwin(struct reg_window
*dst
, struct reg_window
*src
)
404 __asm__
__volatile__("ldd\t[%1 + 0x00], %%g2\n\t"
405 "ldd\t[%1 + 0x08], %%g4\n\t"
406 "ldd\t[%1 + 0x10], %%o4\n\t"
407 "std\t%%g2, [%0 + 0x00]\n\t"
408 "std\t%%g4, [%0 + 0x08]\n\t"
409 "std\t%%o4, [%0 + 0x10]\n\t"
410 "ldd\t[%1 + 0x18], %%g2\n\t"
411 "ldd\t[%1 + 0x20], %%g4\n\t"
412 "ldd\t[%1 + 0x28], %%o4\n\t"
413 "std\t%%g2, [%0 + 0x18]\n\t"
414 "std\t%%g4, [%0 + 0x20]\n\t"
415 "std\t%%o4, [%0 + 0x28]\n\t"
416 "ldd\t[%1 + 0x30], %%g2\n\t"
417 "ldd\t[%1 + 0x38], %%g4\n\t"
418 "std\t%%g2, [%0 + 0x30]\n\t"
419 "std\t%%g4, [%0 + 0x38]\n\t" : :
420 "r" (dst
), "r" (src
) :
421 "g2", "g3", "g4", "g5", "o4", "o5");
424 static __inline__
struct sparc_stackf
*
425 clone_stackframe(struct sparc_stackf
*dst
, struct sparc_stackf
*src
)
428 struct sparc_stackf
*sp
;
430 size
= ((unsigned long)src
->fp
) - ((unsigned long)src
);
431 sp
= (struct sparc_stackf
*)(((unsigned long)dst
) - size
);
433 /* do_fork() grabs the parent semaphore, we must release it
434 * temporarily so we can build the child clone stack frame
435 * without deadlocking.
437 if (copy_to_user(sp
, src
, size
))
438 sp
= (struct sparc_stackf
*) 0;
439 else if (put_user(dst
, &sp
->fp
))
440 sp
= (struct sparc_stackf
*) 0;
446 /* Copy a Sparc thread. The fork() return value conventions
447 * under SunOS are nothing short of bletcherous:
448 * Parent --> %o0 == childs pid, %o1 == 0
449 * Child --> %o0 == parents pid, %o1 == 1
451 * NOTE: We have a separate fork kpsr/kwim because
452 * the parent could change these values between
453 * sys_fork invocation and when we reach here
454 * if the parent should sleep while trying to
455 * allocate the task_struct and kernel stack in
459 extern void ret_from_smpfork(void);
461 extern void ret_from_syscall(void);
464 int copy_thread(int nr
, unsigned long clone_flags
, unsigned long sp
,
465 struct task_struct
*p
, struct pt_regs
*regs
)
467 struct pt_regs
*childregs
;
468 struct reg_window
*new_stack
;
469 unsigned long stack_offset
;
472 if(last_task_used_math
== current
) {
474 if(current
->flags
& PF_USEDFPU
) {
476 put_psr(get_psr() | PSR_EF
);
477 fpsave(&p
->thread
.float_regs
[0], &p
->thread
.fsr
,
478 &p
->thread
.fpqueue
[0], &p
->thread
.fpqdepth
);
480 current
->flags
&= ~PF_USEDFPU
;
484 /* Calculate offset to stack_frame & pt_regs */
485 stack_offset
= TASK_UNION_SIZE
- TRACEREG_SZ
;
487 if(regs
->psr
& PSR_PS
)
488 stack_offset
-= REGWIN_SZ
;
489 childregs
= ((struct pt_regs
*) (((unsigned long)p
) + stack_offset
));
490 copy_regs(childregs
, regs
);
491 new_stack
= (((struct reg_window
*) childregs
) - 1);
492 copy_regwin(new_stack
, (((struct reg_window
*) regs
) - 1));
494 p
->thread
.ksp
= (unsigned long) new_stack
;
496 p
->thread
.kpc
= (((unsigned long) ret_from_smpfork
) - 0x8);
497 p
->thread
.kpsr
= current
->thread
.fork_kpsr
| PSR_PIL
;
499 p
->thread
.kpc
= (((unsigned long) ret_from_syscall
) - 0x8);
500 p
->thread
.kpsr
= current
->thread
.fork_kpsr
;
502 p
->thread
.kwim
= current
->thread
.fork_kwim
;
504 /* This is used for sun4c only */
505 atomic_set(&p
->thread
.refcount
, 1);
507 if(regs
->psr
& PSR_PS
) {
508 extern struct pt_regs fake_swapper_regs
;
510 p
->thread
.kregs
= &fake_swapper_regs
;
511 new_stack
= (struct reg_window
*)
512 ((((unsigned long)p
) +
515 childregs
->u_regs
[UREG_FP
] = (unsigned long) new_stack
;
516 p
->thread
.flags
|= SPARC_FLAG_KTHREAD
;
517 p
->thread
.current_ds
= KERNEL_DS
;
518 memcpy((void *)new_stack
,
519 (void *)regs
->u_regs
[UREG_FP
],
520 sizeof(struct reg_window
));
521 childregs
->u_regs
[UREG_G6
] = (unsigned long) p
;
523 p
->thread
.kregs
= childregs
;
524 childregs
->u_regs
[UREG_FP
] = sp
;
525 p
->thread
.flags
&= ~SPARC_FLAG_KTHREAD
;
526 p
->thread
.current_ds
= USER_DS
;
528 if (sp
!= regs
->u_regs
[UREG_FP
]) {
529 struct sparc_stackf
*childstack
;
530 struct sparc_stackf
*parentstack
;
533 * This is a clone() call with supplied user stack.
534 * Set some valid stack frames to give to the child.
536 childstack
= (struct sparc_stackf
*) (sp
& ~0x7UL
);
537 parentstack
= (struct sparc_stackf
*) regs
->u_regs
[UREG_FP
];
540 printk("clone: parent stack:\n");
541 show_stackframe(parentstack
);
544 childstack
= clone_stackframe(childstack
, parentstack
);
549 printk("clone: child stack:\n");
550 show_stackframe(childstack
);
553 childregs
->u_regs
[UREG_FP
] = (unsigned long)childstack
;
557 /* Set the return value for the child. */
558 childregs
->u_regs
[UREG_I0
] = current
->pid
;
559 childregs
->u_regs
[UREG_I1
] = 1;
561 /* Set the return value for the parent. */
562 regs
->u_regs
[UREG_I1
] = 0;
568 * fill in the user structure for a core dump..
570 void dump_thread(struct pt_regs
* regs
, struct user
* dump
)
572 unsigned long first_stack_page
;
574 dump
->magic
= SUNOS_CORE_MAGIC
;
575 dump
->len
= sizeof(struct user
);
576 dump
->regs
.psr
= regs
->psr
;
577 dump
->regs
.pc
= regs
->pc
;
578 dump
->regs
.npc
= regs
->npc
;
579 dump
->regs
.y
= regs
->y
;
581 memcpy(&dump
->regs
.regs
[0], ®s
->u_regs
[1], (sizeof(unsigned long) * 15));
582 dump
->uexec
= current
->thread
.core_exec
;
583 dump
->u_tsize
= (((unsigned long) current
->mm
->end_code
) -
584 ((unsigned long) current
->mm
->start_code
)) & ~(PAGE_SIZE
- 1);
585 dump
->u_dsize
= ((unsigned long) (current
->mm
->brk
+ (PAGE_SIZE
-1)));
586 dump
->u_dsize
-= dump
->u_tsize
;
587 dump
->u_dsize
&= ~(PAGE_SIZE
- 1);
588 first_stack_page
= (regs
->u_regs
[UREG_FP
] & ~(PAGE_SIZE
- 1));
589 dump
->u_ssize
= (TASK_SIZE
- first_stack_page
) & ~(PAGE_SIZE
- 1);
590 memcpy(&dump
->fpu
.fpstatus
.fregs
.regs
[0], ¤t
->thread
.float_regs
[0], (sizeof(unsigned long) * 32));
591 dump
->fpu
.fpstatus
.fsr
= current
->thread
.fsr
;
592 dump
->fpu
.fpstatus
.flags
= dump
->fpu
.fpstatus
.extra
= 0;
593 dump
->fpu
.fpstatus
.fpq_count
= current
->thread
.fpqdepth
;
594 memcpy(&dump
->fpu
.fpstatus
.fpq
[0], ¤t
->thread
.fpqueue
[0],
595 ((sizeof(unsigned long) * 2) * 16));
600 * fill in the fpu structure for a core dump.
602 int dump_fpu (struct pt_regs
* regs
, elf_fpregset_t
* fpregs
)
604 if (current
->used_math
== 0) {
605 memset(fpregs
, 0, sizeof(*fpregs
));
606 fpregs
->pr_q_entrysize
= 8;
610 if (current
->flags
& PF_USEDFPU
) {
611 put_psr(get_psr() | PSR_EF
);
612 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
613 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
614 regs
->psr
&= ~(PSR_EF
);
615 current
->flags
&= ~(PF_USEDFPU
);
618 if (current
== last_task_used_math
) {
619 put_psr(get_psr() | PSR_EF
);
620 fpsave(¤t
->thread
.float_regs
[0], ¤t
->thread
.fsr
,
621 ¤t
->thread
.fpqueue
[0], ¤t
->thread
.fpqdepth
);
622 last_task_used_math
= 0;
623 regs
->psr
&= ~(PSR_EF
);
626 memcpy(&fpregs
->pr_fr
.pr_regs
[0],
627 ¤t
->thread
.float_regs
[0],
628 (sizeof(unsigned long) * 32));
629 fpregs
->pr_fsr
= current
->thread
.fsr
;
630 fpregs
->pr_qcnt
= current
->thread
.fpqdepth
;
631 fpregs
->pr_q_entrysize
= 8;
633 if(fpregs
->pr_qcnt
!= 0) {
634 memcpy(&fpregs
->pr_q
[0],
635 ¤t
->thread
.fpqueue
[0],
636 sizeof(struct fpq
) * fpregs
->pr_qcnt
);
638 /* Zero out the rest. */
639 memset(&fpregs
->pr_q
[fpregs
->pr_qcnt
], 0,
640 sizeof(struct fpq
) * (32 - fpregs
->pr_qcnt
));
645 * sparc_execve() executes a new program after the asm stub has set
646 * things up for us. This should basically do what I want it to.
648 asmlinkage
int sparc_execve(struct pt_regs
*regs
)
653 /* Check for indirect call. */
654 if(regs
->u_regs
[UREG_G1
] == 0)
657 filename
= getname((char *)regs
->u_regs
[base
+ UREG_I0
]);
658 error
= PTR_ERR(filename
);
661 error
= do_execve(filename
, (char **) regs
->u_regs
[base
+ UREG_I1
],
662 (char **) regs
->u_regs
[base
+ UREG_I2
], regs
);
669 * This is the mechanism for creating a new kernel thread.
671 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
672 * who haven't done an "execve()") should use this: it will work within
673 * a system call from a "real" process, but the process memory space will
674 * not be free'd until both the parent and the child have exited.
676 pid_t
kernel_thread(int (*fn
)(void *), void * arg
, unsigned long flags
)
680 __asm__
__volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */
681 "mov %5, %%g3\n\t" /* and arg. */
683 "mov %2, %%o0\n\t" /* Clone flags. */
684 "mov 0, %%o1\n\t" /* usp arg == 0 */
685 "t 0x10\n\t" /* Linux/Sparc clone(). */
687 "be 1f\n\t" /* The parent, just return. */
688 " nop\n\t" /* Delay slot. */
689 "jmpl %%g2, %%o7\n\t" /* Call the function. */
690 " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
692 "t 0x10\n\t" /* Linux/Sparc exit(). */
693 /* Notreached by child. */
694 "1: mov %%o0, %0\n\t" :
696 "i" (__NR_clone
), "r" (flags
| CLONE_VM
),
697 "i" (__NR_exit
), "r" (fn
), "r" (arg
) :
698 "g1", "g2", "g3", "o0", "o1", "memory", "cc");