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
@ -20,6 +20,7 @@ config ALPHA
|
|||||||
select GENERIC_CMOS_UPDATE
|
select GENERIC_CMOS_UPDATE
|
||||||
select GENERIC_STRNCPY_FROM_USER
|
select GENERIC_STRNCPY_FROM_USER
|
||||||
select GENERIC_STRNLEN_USER
|
select GENERIC_STRNLEN_USER
|
||||||
|
select GENERIC_KERNEL_THREAD
|
||||||
help
|
help
|
||||||
The Alpha is a 64-bit general-purpose processor designed and
|
The Alpha is a 64-bit general-purpose processor designed and
|
||||||
marketed by the Digital Equipment Corporation of blessed memory,
|
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. */
|
/* Free all resources held by a thread. */
|
||||||
extern void release_thread(struct task_struct *);
|
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);
|
unsigned long get_wchan(struct task_struct *p);
|
||||||
|
|
||||||
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
|
#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);
|
||||||
EXPORT_SYMBOL(alpha_write_fp_reg_s);
|
EXPORT_SYMBOL(alpha_write_fp_reg_s);
|
||||||
|
|
||||||
/* entry.S */
|
|
||||||
EXPORT_SYMBOL(kernel_thread);
|
|
||||||
|
|
||||||
/* Networking helper routines. */
|
/* Networking helper routines. */
|
||||||
EXPORT_SYMBOL(csum_tcpudp_magic);
|
EXPORT_SYMBOL(csum_tcpudp_magic);
|
||||||
EXPORT_SYMBOL(ip_compute_csum);
|
EXPORT_SYMBOL(ip_compute_csum);
|
||||||
|
@ -609,59 +609,22 @@ ret_from_fork:
|
|||||||
.end ret_from_fork
|
.end ret_from_fork
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* kernel_thread(fn, arg, clone_flags)
|
* ... and new kernel threads - here
|
||||||
*/
|
*/
|
||||||
.align 4
|
.align 4
|
||||||
.globl kernel_thread
|
.globl ret_from_kernel_thread
|
||||||
.ent kernel_thread
|
.ent ret_from_kernel_thread
|
||||||
kernel_thread:
|
ret_from_kernel_thread:
|
||||||
/* We can be called from a module. */
|
mov $17, $16
|
||||||
ldgp $gp, 0($27)
|
jsr $26, schedule_tail
|
||||||
.prologue 1
|
mov $9, $27
|
||||||
subq $sp, SP_OFF+6*8, $sp
|
mov $10, $16
|
||||||
br $1, 2f /* load start address */
|
jsr $26, ($9)
|
||||||
|
|
||||||
/* 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)
|
|
||||||
ldgp $gp, 0($26)
|
ldgp $gp, 0($26)
|
||||||
mov $0, $16
|
mov $0, $16
|
||||||
mov $31, $26
|
mov $31, $26
|
||||||
jmp $31, sys_exit
|
jmp $31, sys_exit
|
||||||
|
.end ret_from_kernel_thread
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -259,33 +259,35 @@ alpha_vfork(struct pt_regs *regs)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy an alpha thread..
|
* 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
|
int
|
||||||
copy_thread(unsigned long clone_flags, unsigned long usp,
|
copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long unused,
|
unsigned long arg,
|
||||||
struct task_struct * p, struct pt_regs * regs)
|
struct task_struct * p, struct pt_regs * regs)
|
||||||
{
|
{
|
||||||
extern void ret_from_fork(void);
|
extern void ret_from_fork(void);
|
||||||
|
extern void ret_from_kernel_thread(void);
|
||||||
|
|
||||||
struct thread_info *childti = task_thread_info(p);
|
struct thread_info *childti = task_thread_info(p);
|
||||||
struct pt_regs * childregs;
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
struct switch_stack *childstack, *stack;
|
struct switch_stack *childstack, *stack;
|
||||||
unsigned long stack_offset, settls;
|
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;
|
*childregs = *regs;
|
||||||
settls = regs->r20;
|
settls = regs->r20;
|
||||||
childregs->r0 = 0;
|
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. */
|
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
|
||||||
regs->r20 = 0;
|
regs->r20 = 0;
|
||||||
stack = ((struct switch_stack *) regs) - 1;
|
stack = ((struct switch_stack *) regs) - 1;
|
||||||
childstack = ((struct switch_stack *) childregs) - 1;
|
|
||||||
*childstack = *stack;
|
*childstack = *stack;
|
||||||
childstack->r26 = (unsigned long) ret_from_fork;
|
childstack->r26 = (unsigned long) ret_from_fork;
|
||||||
childti->pcb.usp = usp;
|
childti->pcb.usp = usp;
|
||||||
|
Loading…
Reference in New Issue
Block a user