diff options
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/Kconfig | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/processor_32.h | 1 | ||||
-rw-r--r-- | arch/sparc/kernel/entry.S | 10 | ||||
-rw-r--r-- | arch/sparc/kernel/process_32.c | 124 |
4 files changed, 56 insertions, 81 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index e47eb324d77a..edc4ede8ec3e 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -40,6 +40,7 @@ config SPARC | |||
40 | select GENERIC_STRNCPY_FROM_USER | 40 | select GENERIC_STRNCPY_FROM_USER |
41 | select GENERIC_STRNLEN_USER | 41 | select GENERIC_STRNLEN_USER |
42 | select MODULES_USE_ELF_RELA | 42 | select MODULES_USE_ELF_RELA |
43 | select GENERIC_KERNEL_THREAD | ||
43 | 44 | ||
44 | config SPARC32 | 45 | config SPARC32 |
45 | def_bool !64BIT | 46 | def_bool !64BIT |
@@ -74,7 +75,6 @@ config SPARC64 | |||
74 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 75 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
75 | select HAVE_C_RECORDMCOUNT | 76 | select HAVE_C_RECORDMCOUNT |
76 | select NO_BOOTMEM | 77 | select NO_BOOTMEM |
77 | select GENERIC_KERNEL_THREAD | ||
78 | select GENERIC_KERNEL_EXECVE | 78 | select GENERIC_KERNEL_EXECVE |
79 | 79 | ||
80 | config ARCH_DEFCONFIG | 80 | config ARCH_DEFCONFIG |
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index f74ac9ee33a8..c1e01914fd98 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h | |||
@@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, | |||
106 | 106 | ||
107 | /* Free all resources held by a thread. */ | 107 | /* Free all resources held by a thread. */ |
108 | #define release_thread(tsk) do { } while(0) | 108 | #define release_thread(tsk) do { } while(0) |
109 | extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
110 | 109 | ||
111 | extern unsigned long get_wchan(struct task_struct *); | 110 | extern unsigned long get_wchan(struct task_struct *); |
112 | 111 | ||
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index dc089702e00a..6114672a1b0e 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -983,6 +983,16 @@ ret_from_fork: | |||
983 | b ret_sys_call | 983 | b ret_sys_call |
984 | ld [%sp + STACKFRAME_SZ + PT_I0], %o0 | 984 | ld [%sp + STACKFRAME_SZ + PT_I0], %o0 |
985 | 985 | ||
986 | .globl ret_from_kernel_thread | ||
987 | ret_from_kernel_thread: | ||
988 | call schedule_tail | ||
989 | ld [%g3 + TI_TASK], %o0 | ||
990 | ld [%sp + STACKFRAME_SZ + PT_G1], %l0 | ||
991 | call %l0 | ||
992 | ld [%sp + STACKFRAME_SZ + PT_G2], %o0 | ||
993 | call do_exit /* won't return */ | ||
994 | clr %o0 | ||
995 | |||
986 | /* Linux native system calls enter here... */ | 996 | /* Linux native system calls enter here... */ |
987 | .align 4 | 997 | .align 4 |
988 | .globl linux_sparc_syscall | 998 | .globl linux_sparc_syscall |
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 487bffb36f5e..72764356d308 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c | |||
@@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, | |||
316 | * XXX See comment above sys_vfork in sparc64. todo. | 316 | * XXX See comment above sys_vfork in sparc64. todo. |
317 | */ | 317 | */ |
318 | extern void ret_from_fork(void); | 318 | extern void ret_from_fork(void); |
319 | extern void ret_from_kernel_thread(void); | ||
319 | 320 | ||
320 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 321 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
321 | unsigned long unused, | 322 | unsigned long arg, |
322 | struct task_struct *p, struct pt_regs *regs) | 323 | struct task_struct *p, struct pt_regs *regs) |
323 | { | 324 | { |
324 | struct thread_info *ti = task_thread_info(p); | 325 | struct thread_info *ti = task_thread_info(p); |
@@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
336 | } | 337 | } |
337 | 338 | ||
338 | /* | 339 | /* |
339 | * p->thread_info new_stack childregs | 340 | * p->thread_info new_stack childregs stack bottom |
340 | * ! ! ! {if(PSR_PS) } | 341 | * ! ! ! ! |
341 | * V V (stk.fr.) V (pt_regs) { (stk.fr.) } | 342 | * V V (stk.fr.) V (pt_regs) V |
342 | * +----- - - - - - ------+===========+============={+==========}+ | 343 | * +----- - - - - - ------+===========+=============+ |
343 | */ | 344 | */ |
344 | new_stack = task_stack_page(p) + THREAD_SIZE; | 345 | new_stack = task_stack_page(p) + THREAD_SIZE; |
345 | if (regs->psr & PSR_PS) | ||
346 | new_stack -= STACKFRAME_SZ; | ||
347 | new_stack -= STACKFRAME_SZ + TRACEREG_SZ; | 346 | new_stack -= STACKFRAME_SZ + TRACEREG_SZ; |
348 | memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); | ||
349 | childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); | 347 | childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); |
350 | 348 | ||
351 | /* | 349 | /* |
@@ -356,55 +354,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
356 | * Thus, kpsr|=PSR_PIL. | 354 | * Thus, kpsr|=PSR_PIL. |
357 | */ | 355 | */ |
358 | ti->ksp = (unsigned long) new_stack; | 356 | ti->ksp = (unsigned long) new_stack; |
357 | p->thread.kregs = childregs; | ||
358 | |||
359 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
360 | extern int nwindows; | ||
361 | unsigned long psr; | ||
362 | memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ); | ||
363 | p->thread.flags |= SPARC_FLAG_KTHREAD; | ||
364 | p->thread.current_ds = KERNEL_DS; | ||
365 | ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8); | ||
366 | childregs->u_regs[UREG_G1] = sp; /* function */ | ||
367 | childregs->u_regs[UREG_G2] = arg; | ||
368 | psr = childregs->psr = get_psr(); | ||
369 | ti->kpsr = psr | PSR_PIL; | ||
370 | ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows); | ||
371 | return 0; | ||
372 | } | ||
373 | memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); | ||
374 | childregs->u_regs[UREG_FP] = sp; | ||
375 | p->thread.flags &= ~SPARC_FLAG_KTHREAD; | ||
376 | p->thread.current_ds = USER_DS; | ||
359 | ti->kpc = (((unsigned long) ret_from_fork) - 0x8); | 377 | ti->kpc = (((unsigned long) ret_from_fork) - 0x8); |
360 | ti->kpsr = current->thread.fork_kpsr | PSR_PIL; | 378 | ti->kpsr = current->thread.fork_kpsr | PSR_PIL; |
361 | ti->kwim = current->thread.fork_kwim; | 379 | ti->kwim = current->thread.fork_kwim; |
362 | 380 | ||
363 | if(regs->psr & PSR_PS) { | 381 | if (sp != regs->u_regs[UREG_FP]) { |
364 | extern struct pt_regs fake_swapper_regs; | 382 | struct sparc_stackf __user *childstack; |
383 | struct sparc_stackf __user *parentstack; | ||
365 | 384 | ||
366 | p->thread.kregs = &fake_swapper_regs; | 385 | /* |
367 | new_stack += STACKFRAME_SZ + TRACEREG_SZ; | 386 | * This is a clone() call with supplied user stack. |
368 | childregs->u_regs[UREG_FP] = (unsigned long) new_stack; | 387 | * Set some valid stack frames to give to the child. |
369 | p->thread.flags |= SPARC_FLAG_KTHREAD; | 388 | */ |
370 | p->thread.current_ds = KERNEL_DS; | 389 | childstack = (struct sparc_stackf __user *) |
371 | memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); | 390 | (sp & ~0xfUL); |
372 | childregs->u_regs[UREG_G6] = (unsigned long) ti; | 391 | parentstack = (struct sparc_stackf __user *) |
373 | } else { | 392 | regs->u_regs[UREG_FP]; |
374 | p->thread.kregs = childregs; | ||
375 | childregs->u_regs[UREG_FP] = sp; | ||
376 | p->thread.flags &= ~SPARC_FLAG_KTHREAD; | ||
377 | p->thread.current_ds = USER_DS; | ||
378 | |||
379 | if (sp != regs->u_regs[UREG_FP]) { | ||
380 | struct sparc_stackf __user *childstack; | ||
381 | struct sparc_stackf __user *parentstack; | ||
382 | |||
383 | /* | ||
384 | * This is a clone() call with supplied user stack. | ||
385 | * Set some valid stack frames to give to the child. | ||
386 | */ | ||
387 | childstack = (struct sparc_stackf __user *) | ||
388 | (sp & ~0xfUL); | ||
389 | parentstack = (struct sparc_stackf __user *) | ||
390 | regs->u_regs[UREG_FP]; | ||
391 | 393 | ||
392 | #if 0 | 394 | #if 0 |
393 | printk("clone: parent stack:\n"); | 395 | printk("clone: parent stack:\n"); |
394 | show_stackframe(parentstack); | 396 | show_stackframe(parentstack); |
395 | #endif | 397 | #endif |
396 | 398 | ||
397 | childstack = clone_stackframe(childstack, parentstack); | 399 | childstack = clone_stackframe(childstack, parentstack); |
398 | if (!childstack) | 400 | if (!childstack) |
399 | return -EFAULT; | 401 | return -EFAULT; |
400 | 402 | ||
401 | #if 0 | 403 | #if 0 |
402 | printk("clone: child stack:\n"); | 404 | printk("clone: child stack:\n"); |
403 | show_stackframe(childstack); | 405 | show_stackframe(childstack); |
404 | #endif | 406 | #endif |
405 | 407 | ||
406 | childregs->u_regs[UREG_FP] = (unsigned long)childstack; | 408 | childregs->u_regs[UREG_FP] = (unsigned long)childstack; |
407 | } | ||
408 | } | 409 | } |
409 | 410 | ||
410 | #ifdef CONFIG_SMP | 411 | #ifdef CONFIG_SMP |
@@ -503,41 +504,6 @@ out: | |||
503 | return error; | 504 | return error; |
504 | } | 505 | } |
505 | 506 | ||
506 | /* | ||
507 | * This is the mechanism for creating a new kernel thread. | ||
508 | * | ||
509 | * NOTE! Only a kernel-only process(ie the swapper or direct descendants | ||
510 | * who haven't done an "execve()") should use this: it will work within | ||
511 | * a system call from a "real" process, but the process memory space will | ||
512 | * not be freed until both the parent and the child have exited. | ||
513 | */ | ||
514 | pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
515 | { | ||
516 | long retval; | ||
517 | |||
518 | __asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */ | ||
519 | "mov %5, %%g3\n\t" /* and arg. */ | ||
520 | "mov %1, %%g1\n\t" | ||
521 | "mov %2, %%o0\n\t" /* Clone flags. */ | ||
522 | "mov 0, %%o1\n\t" /* usp arg == 0 */ | ||
523 | "t 0x10\n\t" /* Linux/Sparc clone(). */ | ||
524 | "cmp %%o1, 0\n\t" | ||
525 | "be 1f\n\t" /* The parent, just return. */ | ||
526 | " nop\n\t" /* Delay slot. */ | ||
527 | "jmpl %%g2, %%o7\n\t" /* Call the function. */ | ||
528 | " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ | ||
529 | "mov %3, %%g1\n\t" | ||
530 | "t 0x10\n\t" /* Linux/Sparc exit(). */ | ||
531 | /* Notreached by child. */ | ||
532 | "1: mov %%o0, %0\n\t" : | ||
533 | "=r" (retval) : | ||
534 | "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), | ||
535 | "i" (__NR_exit), "r" (fn), "r" (arg) : | ||
536 | "g1", "g2", "g3", "o0", "o1", "memory", "cc"); | ||
537 | return retval; | ||
538 | } | ||
539 | EXPORT_SYMBOL(kernel_thread); | ||
540 | |||
541 | unsigned long get_wchan(struct task_struct *task) | 507 | unsigned long get_wchan(struct task_struct *task) |
542 | { | 508 | { |
543 | unsigned long pc, fp, bias = 0; | 509 | unsigned long pc, fp, bias = 0; |