alpha: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
756144f8ea
commit
cba1ec7e88
5 changed files with 30 additions and 71 deletions
|
@ -20,6 +20,7 @@ config ALPHA
|
|||
select GENERIC_CMOS_UPDATE
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
select GENERIC_KERNEL_THREAD
|
||||
help
|
||||
The Alpha is a 64-bit general-purpose processor designed and
|
||||
marketed by the Digital Equipment Corporation of blessed memory,
|
||||
|
|
|
@ -49,9 +49,6 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
|
|||
/* Free all resources held by a thread. */
|
||||
extern void release_thread(struct task_struct *);
|
||||
|
||||
/* Create a kernel thread without removing it from tasklists. */
|
||||
extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
|
||||
|
||||
unsigned long get_wchan(struct task_struct *p);
|
||||
|
||||
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
|
||||
|
|
|
@ -50,9 +50,6 @@ EXPORT_SYMBOL(alpha_read_fp_reg_s);
|
|||
EXPORT_SYMBOL(alpha_write_fp_reg);
|
||||
EXPORT_SYMBOL(alpha_write_fp_reg_s);
|
||||
|
||||
/* entry.S */
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
/* Networking helper routines. */
|
||||
EXPORT_SYMBOL(csum_tcpudp_magic);
|
||||
EXPORT_SYMBOL(ip_compute_csum);
|
||||
|
|
|
@ -609,59 +609,22 @@ ret_from_fork:
|
|||
.end ret_from_fork
|
||||
|
||||
/*
|
||||
* kernel_thread(fn, arg, clone_flags)
|
||||
* ... and new kernel threads - here
|
||||
*/
|
||||
.align 4
|
||||
.globl kernel_thread
|
||||
.ent kernel_thread
|
||||
kernel_thread:
|
||||
/* We can be called from a module. */
|
||||
ldgp $gp, 0($27)
|
||||
.prologue 1
|
||||
subq $sp, SP_OFF+6*8, $sp
|
||||
br $1, 2f /* load start address */
|
||||
|
||||
/* We've now "returned" from a fake system call. */
|
||||
unop
|
||||
blt $0, 1f /* error? */
|
||||
ldi $1, 0x3fff
|
||||
beq $20, 1f /* parent or child? */
|
||||
|
||||
bic $sp, $1, $8 /* in child. */
|
||||
jsr $26, ($27)
|
||||
.globl ret_from_kernel_thread
|
||||
.ent ret_from_kernel_thread
|
||||
ret_from_kernel_thread:
|
||||
mov $17, $16
|
||||
jsr $26, schedule_tail
|
||||
mov $9, $27
|
||||
mov $10, $16
|
||||
jsr $26, ($9)
|
||||
ldgp $gp, 0($26)
|
||||
mov $0, $16
|
||||
mov $31, $26
|
||||
jmp $31, sys_exit
|
||||
|
||||
1: ret /* in parent. */
|
||||
|
||||
.align 4
|
||||
2: /* Fake a system call stack frame, as we can't do system calls
|
||||
from kernel space. Note that we store FN and ARG as they
|
||||
need to be set up in the child for the call. Also store $8
|
||||
and $26 for use in the parent. */
|
||||
stq $31, SP_OFF($sp) /* ps */
|
||||
stq $1, SP_OFF+8($sp) /* pc */
|
||||
stq $gp, SP_OFF+16($sp) /* gp */
|
||||
stq $16, 136($sp) /* $27; FN for child */
|
||||
stq $17, SP_OFF+24($sp) /* $16; ARG for child */
|
||||
stq $8, 64($sp) /* $8 */
|
||||
stq $26, 128($sp) /* $26 */
|
||||
/* Avoid the HAE being gratuitously wrong, to avoid restoring it. */
|
||||
ldq $2, alpha_mv+HAE_CACHE
|
||||
stq $2, 152($sp) /* HAE */
|
||||
|
||||
/* Shuffle FLAGS to the front; add CLONE_VM. */
|
||||
ldi $1, CLONE_VM|CLONE_UNTRACED
|
||||
or $18, $1, $16
|
||||
bsr $26, sys_clone
|
||||
|
||||
/* We don't actually care for a3 success widgetry in the kernel.
|
||||
Not for positive errno values. */
|
||||
stq $0, 0($sp) /* $0 */
|
||||
br ret_to_kernel
|
||||
.end kernel_thread
|
||||
.end ret_from_kernel_thread
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -259,33 +259,35 @@ alpha_vfork(struct pt_regs *regs)
|
|||
|
||||
/*
|
||||
* Copy an alpha thread..
|
||||
*
|
||||
* Note the "stack_offset" stuff: when returning to kernel mode, we need
|
||||
* to have some extra stack-space for the kernel stack that still exists
|
||||
* after the "ret_from_fork". When returning to user mode, we only want
|
||||
* the space needed by the syscall stack frame (ie "struct pt_regs").
|
||||
* Use the passed "regs" pointer to determine how much space we need
|
||||
* for a kernel fork().
|
||||
*/
|
||||
|
||||
int
|
||||
copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||
unsigned long unused,
|
||||
unsigned long arg,
|
||||
struct task_struct * p, struct pt_regs * regs)
|
||||
{
|
||||
extern void ret_from_fork(void);
|
||||
extern void ret_from_kernel_thread(void);
|
||||
|
||||
struct thread_info *childti = task_thread_info(p);
|
||||
struct pt_regs * childregs;
|
||||
struct switch_stack * childstack, *stack;
|
||||
unsigned long stack_offset, settls;
|
||||
struct pt_regs *childregs = task_pt_regs(p);
|
||||
struct switch_stack *childstack, *stack;
|
||||
unsigned long settls;
|
||||
|
||||
stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
|
||||
if (!(regs->ps & 8))
|
||||
stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
|
||||
childregs = (struct pt_regs *)
|
||||
(stack_offset + PAGE_SIZE + task_stack_page(p));
|
||||
|
||||
childstack = ((struct switch_stack *) childregs) - 1;
|
||||
if (unlikely(!regs)) {
|
||||
/* kernel thread */
|
||||
memset(childstack, 0,
|
||||
sizeof(struct switch_stack) + sizeof(struct pt_regs));
|
||||
childstack->r26 = (unsigned long) ret_from_kernel_thread;
|
||||
childstack->r9 = usp; /* function */
|
||||
childstack->r10 = arg;
|
||||
childregs->hae = alpha_mv.hae_cache,
|
||||
childti->pcb.usp = 0;
|
||||
childti->pcb.ksp = (unsigned long) childstack;
|
||||
childti->pcb.flags = 1; /* set FEN, clear everything else */
|
||||
return 0;
|
||||
}
|
||||
*childregs = *regs;
|
||||
settls = regs->r20;
|
||||
childregs->r0 = 0;
|
||||
|
@ -293,7 +295,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
|
|||
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
|
||||
regs->r20 = 0;
|
||||
stack = ((struct switch_stack *) regs) - 1;
|
||||
childstack = ((struct switch_stack *) childregs) - 1;
|
||||
*childstack = *stack;
|
||||
childstack->r26 = (unsigned long) ret_from_fork;
|
||||
childti->pcb.usp = usp;
|
||||
|
|
Loading…
Reference in a new issue