summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/include/asm/processor.h3
-rw-r--r--arch/powerpc/kernel/entry_32.S11
-rw-r--r--arch/powerpc/kernel/entry_64.S10
-rw-r--r--arch/powerpc/kernel/misc_32.S33
-rw-r--r--arch/powerpc/kernel/misc_64.S34
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c1
-rw-r--r--arch/powerpc/kernel/process.c34
8 files changed, 43 insertions, 84 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 352f416269ce..6e5a0979c085 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -139,6 +139,7 @@ config PPC
select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
+ select GENERIC_KERNEL_THREAD
config EARLY_PRINTK
bool
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 54b73a28c205..5376453d90cc 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -74,9 +74,6 @@ struct task_struct;
void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
void release_thread(struct task_struct *);
-/* Create a new kernel thread. */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
/* Lazy FPU handling on uni-processor */
extern struct task_struct *last_task_used_math;
extern struct task_struct *last_task_used_altivec;
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index ead5016b02d0..6eb330a87c36 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -435,6 +435,17 @@ ret_from_fork:
li r3,0
b ret_from_syscall
+ .globl ret_from_kernel_thread
+ret_from_kernel_thread:
+ REST_NVGPRS(r1)
+ bl schedule_tail
+ mtlr r14
+ mr r3,r15
+ PPC440EP_ERR42
+ blrl
+ li r3,0
+ b do_exit # no return
+
/* Traced system call support */
syscall_dotrace:
SAVE_NVGPRS(r1)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index b40e0b4815b3..d7f4fafc7515 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -370,6 +370,16 @@ _GLOBAL(ret_from_fork)
li r3,0
b syscall_exit
+_GLOBAL(ret_from_kernel_thread)
+ bl .schedule_tail
+ REST_NVGPRS(r1)
+ REST_GPR(2,r1)
+ mtlr r14
+ mr r3,r15
+ blrl
+ li r3,0
+ b .do_exit # no return
+
.section ".toc","aw"
DSCR_DEFAULT:
.tc dscr_default[TC],dscr_default
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 407e293aad2f..19e096bd0e73 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -663,39 +663,6 @@ _GLOBAL(abs)
sub r3,r3,r4
blr
-/*
- * Create a kernel thread
- * kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
- stwu r1,-16(r1)
- stw r30,8(r1)
- stw r31,12(r1)
- mr r30,r3 /* function */
- mr r31,r4 /* argument */
- ori r3,r5,CLONE_VM /* flags */
- oris r3,r3,CLONE_UNTRACED>>16
- li r4,0 /* new sp (unused) */
- li r0,__NR_clone
- sc
- bns+ 1f /* did system call indicate error? */
- neg r3,r3 /* if so, make return code negative */
-1: cmpwi 0,r3,0 /* parent or child? */
- bne 2f /* return if parent */
- li r0,0 /* make top-level stack frame */
- stwu r0,-16(r1)
- mtlr r30 /* fn addr in lr */
- mr r3,r31 /* load arg and call fn */
- PPC440EP_ERR42
- blrl
- li r0,__NR_exit /* exit if function returns */
- li r3,0
- sc
-2: lwz r30,8(r1)
- lwz r31,12(r1)
- addi r1,r1,16
- blr
-
#ifdef CONFIG_SMP
_GLOBAL(start_secondary_resume)
/* Reset stack */
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 565b78625a32..5cfa8008693b 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -407,40 +407,6 @@ _GLOBAL(scom970_write)
/*
- * Create a kernel thread
- * kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
- std r29,-24(r1)
- std r30,-16(r1)
- stdu r1,-STACK_FRAME_OVERHEAD(r1)
- mr r29,r3
- mr r30,r4
- ori r3,r5,CLONE_VM /* flags */
- oris r3,r3,(CLONE_UNTRACED>>16)
- li r4,0 /* new sp (unused) */
- li r0,__NR_clone
- sc
- bns+ 1f /* did system call indicate error? */
- neg r3,r3 /* if so, make return code negative */
-1: cmpdi 0,r3,0 /* parent or child? */
- bne 2f /* return if parent */
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
- ld r2,8(r29)
- ld r29,0(r29)
- mtlr r29 /* fn addr in lr */
- mr r3,r30 /* load arg and call fn */
- blrl
- li r0,__NR_exit /* exit after child exits */
- li r3,0
- sc
-2: addi r1,r1,STACK_FRAME_OVERHEAD
- ld r29,-24(r1)
- ld r30,-16(r1)
- blr
-
-/*
* disable_kernel_fp()
* Disable the FPU.
*/
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 3e4031581c65..19e4288d8486 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -94,7 +94,6 @@ EXPORT_SYMBOL(pci_dram_offset);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL(start_thread);
-EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(giveup_fpu);
#ifdef CONFIG_ALTIVEC
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 1a1f2ddfb581..3b06898fa175 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -734,30 +734,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
int copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, struct task_struct *p,
+ unsigned long arg, struct task_struct *p,
struct pt_regs *regs)
{
struct pt_regs *childregs, *kregs;
extern void ret_from_fork(void);
+ extern void ret_from_kernel_thread(void);
+ void (*f)(void);
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
- CHECK_FULL_REGS(regs);
/* Copy registers */
sp -= sizeof(struct pt_regs);
childregs = (struct pt_regs *) sp;
- *childregs = *regs;
- if ((childregs->msr & MSR_PR) == 0) {
+ if (!regs) {
/* for kernel thread, set `current' and stackptr in new task */
+ memset(childregs, 0, sizeof(struct pt_regs));
childregs->gpr[1] = sp + sizeof(struct pt_regs);
-#ifdef CONFIG_PPC32
- childregs->gpr[2] = (unsigned long) p;
-#else
+#ifdef CONFIG_PPC64
+ childregs->gpr[14] = *(unsigned long *)usp;
+ childregs->gpr[2] = ((unsigned long *)usp)[1],
clear_tsk_thread_flag(p, TIF_32BIT);
+#else
+ childregs->gpr[14] = usp; /* function */
+ childregs->gpr[2] = (unsigned long) p;
#endif
+ childregs->gpr[15] = arg;
p->thread.regs = NULL; /* no user register state */
+ f = ret_from_kernel_thread;
} else {
+ CHECK_FULL_REGS(regs);
+ *childregs = *regs;
childregs->gpr[1] = usp;
p->thread.regs = childregs;
+ childregs->gpr[3] = 0; /* Result from fork() */
if (clone_flags & CLONE_SETTLS) {
#ifdef CONFIG_PPC64
if (!is_32bit_task())
@@ -766,8 +775,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
#endif
childregs->gpr[2] = childregs->gpr[6];
}
+
+ f = ret_from_fork;
}
- childregs->gpr[3] = 0; /* Result from fork() */
sp -= STACK_FRAME_OVERHEAD;
/*
@@ -806,19 +816,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
p->thread.dscr = current->thread.dscr;
}
#endif
-
/*
* The PPC64 ABI makes use of a TOC to contain function
* pointers. The function (ret_from_except) is actually a pointer
* to the TOC entry. The first entry is a pointer to the actual
* function.
- */
+ */
#ifdef CONFIG_PPC64
- kregs->nip = *((unsigned long *)ret_from_fork);
+ kregs->nip = *((unsigned long *)f);
#else
- kregs->nip = (unsigned long)ret_from_fork;
+ kregs->nip = (unsigned long)f;
#endif
-
return 0;
}