mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-26 18:43:33 -05:00
powerpc: split ret_from_fork
... and get rid of in-kernel syscalls in kernel_thread() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
f322220d61
commit
58254e1002
8 changed files with 43 additions and 84 deletions
|
@ -139,6 +139,7 @@ config PPC
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
select GENERIC_STRNCPY_FROM_USER
|
select GENERIC_STRNCPY_FROM_USER
|
||||||
select GENERIC_STRNLEN_USER
|
select GENERIC_STRNLEN_USER
|
||||||
|
select GENERIC_KERNEL_THREAD
|
||||||
|
|
||||||
config EARLY_PRINTK
|
config EARLY_PRINTK
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -74,9 +74,6 @@ struct task_struct;
|
||||||
void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
|
void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
|
||||||
void release_thread(struct task_struct *);
|
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 */
|
/* Lazy FPU handling on uni-processor */
|
||||||
extern struct task_struct *last_task_used_math;
|
extern struct task_struct *last_task_used_math;
|
||||||
extern struct task_struct *last_task_used_altivec;
|
extern struct task_struct *last_task_used_altivec;
|
||||||
|
|
|
@ -435,6 +435,17 @@ ret_from_fork:
|
||||||
li r3,0
|
li r3,0
|
||||||
b ret_from_syscall
|
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 */
|
/* Traced system call support */
|
||||||
syscall_dotrace:
|
syscall_dotrace:
|
||||||
SAVE_NVGPRS(r1)
|
SAVE_NVGPRS(r1)
|
||||||
|
|
|
@ -370,6 +370,16 @@ _GLOBAL(ret_from_fork)
|
||||||
li r3,0
|
li r3,0
|
||||||
b syscall_exit
|
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"
|
.section ".toc","aw"
|
||||||
DSCR_DEFAULT:
|
DSCR_DEFAULT:
|
||||||
.tc dscr_default[TC],dscr_default
|
.tc dscr_default[TC],dscr_default
|
||||||
|
|
|
@ -663,39 +663,6 @@ _GLOBAL(abs)
|
||||||
sub r3,r3,r4
|
sub r3,r3,r4
|
||||||
blr
|
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
|
#ifdef CONFIG_SMP
|
||||||
_GLOBAL(start_secondary_resume)
|
_GLOBAL(start_secondary_resume)
|
||||||
/* Reset stack */
|
/* Reset stack */
|
||||||
|
|
|
@ -406,40 +406,6 @@ _GLOBAL(scom970_write)
|
||||||
#endif /* CONFIG_CPU_FREQ_PMAC64 || CONFIG_CPU_FREQ_MAPLE */
|
#endif /* CONFIG_CPU_FREQ_PMAC64 || CONFIG_CPU_FREQ_MAPLE */
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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_kernel_fp()
|
||||||
* Disable the FPU.
|
* Disable the FPU.
|
||||||
|
|
|
@ -94,7 +94,6 @@ EXPORT_SYMBOL(pci_dram_offset);
|
||||||
#endif /* CONFIG_PCI */
|
#endif /* CONFIG_PCI */
|
||||||
|
|
||||||
EXPORT_SYMBOL(start_thread);
|
EXPORT_SYMBOL(start_thread);
|
||||||
EXPORT_SYMBOL(kernel_thread);
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(giveup_fpu);
|
EXPORT_SYMBOL(giveup_fpu);
|
||||||
#ifdef CONFIG_ALTIVEC
|
#ifdef CONFIG_ALTIVEC
|
||||||
|
|
|
@ -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 */
|
extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
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 *regs)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs, *kregs;
|
struct pt_regs *childregs, *kregs;
|
||||||
extern void ret_from_fork(void);
|
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;
|
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
|
||||||
|
|
||||||
CHECK_FULL_REGS(regs);
|
|
||||||
/* Copy registers */
|
/* Copy registers */
|
||||||
sp -= sizeof(struct pt_regs);
|
sp -= sizeof(struct pt_regs);
|
||||||
childregs = (struct pt_regs *) sp;
|
childregs = (struct pt_regs *) sp;
|
||||||
*childregs = *regs;
|
if (!regs) {
|
||||||
if ((childregs->msr & MSR_PR) == 0) {
|
|
||||||
/* for kernel thread, set `current' and stackptr in new task */
|
/* 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);
|
childregs->gpr[1] = sp + sizeof(struct pt_regs);
|
||||||
#ifdef CONFIG_PPC32
|
#ifdef CONFIG_PPC64
|
||||||
childregs->gpr[2] = (unsigned long) p;
|
childregs->gpr[14] = *(unsigned long *)usp;
|
||||||
#else
|
childregs->gpr[2] = ((unsigned long *)usp)[1],
|
||||||
clear_tsk_thread_flag(p, TIF_32BIT);
|
clear_tsk_thread_flag(p, TIF_32BIT);
|
||||||
|
#else
|
||||||
|
childregs->gpr[14] = usp; /* function */
|
||||||
|
childregs->gpr[2] = (unsigned long) p;
|
||||||
#endif
|
#endif
|
||||||
|
childregs->gpr[15] = arg;
|
||||||
p->thread.regs = NULL; /* no user register state */
|
p->thread.regs = NULL; /* no user register state */
|
||||||
|
f = ret_from_kernel_thread;
|
||||||
} else {
|
} else {
|
||||||
|
CHECK_FULL_REGS(regs);
|
||||||
|
*childregs = *regs;
|
||||||
childregs->gpr[1] = usp;
|
childregs->gpr[1] = usp;
|
||||||
p->thread.regs = childregs;
|
p->thread.regs = childregs;
|
||||||
|
childregs->gpr[3] = 0; /* Result from fork() */
|
||||||
if (clone_flags & CLONE_SETTLS) {
|
if (clone_flags & CLONE_SETTLS) {
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
if (!is_32bit_task())
|
if (!is_32bit_task())
|
||||||
|
@ -766,8 +775,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
#endif
|
#endif
|
||||||
childregs->gpr[2] = childregs->gpr[6];
|
childregs->gpr[2] = childregs->gpr[6];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f = ret_from_fork;
|
||||||
}
|
}
|
||||||
childregs->gpr[3] = 0; /* Result from fork() */
|
|
||||||
sp -= STACK_FRAME_OVERHEAD;
|
sp -= STACK_FRAME_OVERHEAD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -806,19 +816,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
p->thread.dscr = current->thread.dscr;
|
p->thread.dscr = current->thread.dscr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The PPC64 ABI makes use of a TOC to contain function
|
* The PPC64 ABI makes use of a TOC to contain function
|
||||||
* pointers. The function (ret_from_except) is actually a pointer
|
* pointers. The function (ret_from_except) is actually a pointer
|
||||||
* to the TOC entry. The first entry is a pointer to the actual
|
* to the TOC entry. The first entry is a pointer to the actual
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
kregs->nip = *((unsigned long *)ret_from_fork);
|
kregs->nip = *((unsigned long *)f);
|
||||||
#else
|
#else
|
||||||
kregs->nip = (unsigned long)ret_from_fork;
|
kregs->nip = (unsigned long)f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue