Factor out code to setup lwp u-area into a separate function used by
both cpu_lwp_fork and cpu_setfunc.
This commit is contained in:
parent
a86741016f
commit
9ad0553da6
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: vm_machdep.c,v 1.58 2007/08/17 23:58:47 ad Exp $ */
|
||||
/* $NetBSD: vm_machdep.c,v 1.59 2007/08/21 01:13:05 uwe Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved.
|
||||
|
@ -81,7 +81,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.58 2007/08/17 23:58:47 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.59 2007/08/21 01:13:05 uwe Exp $");
|
||||
|
||||
#include "opt_kstack_debug.h"
|
||||
#include "opt_coredump.h"
|
||||
|
@ -108,27 +108,82 @@ __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.58 2007/08/17 23:58:47 ad Exp $");
|
|||
extern void lwp_trampoline(void);
|
||||
extern void lwp_setfunc_trampoline(void);
|
||||
|
||||
static void sh3_setup_uarea(struct lwp *);
|
||||
|
||||
|
||||
/*
|
||||
* Finish a fork operation, with process p2 nearly set up.
|
||||
* Copy and update the pcb and trap frame, making the child ready to run.
|
||||
* Finish a fork operation, with lwp l2 nearly set up. Copy and
|
||||
* update the pcb and trap frame, making the child ready to run.
|
||||
*
|
||||
* Rig the child's kernel stack so that it will start out in
|
||||
* lwp_trampoline() and call child_return() with p2 as an
|
||||
* argument. This causes the newly-created child process to go
|
||||
* directly to user level with an apparent return value of 0 from
|
||||
* fork(), while the parent process returns normally.
|
||||
* lwp_trampoline() and call child_return() with l2 as an argument.
|
||||
* This causes the newly-created lwp to go directly to user level with
|
||||
* an apparent return value of 0 from fork(), while the parent lwp
|
||||
* returns normally.
|
||||
*
|
||||
* p1 is the process being forked; if p1 == &proc0, we are creating
|
||||
* a kernel thread, and the return path and argument are specified with
|
||||
* l1 is the lwp being forked; if l1 == &lwp0, we are creating a
|
||||
* kernel thread, and the return path and argument are specified with
|
||||
* `func' and `arg'.
|
||||
*
|
||||
* If an alternate user-level stack is requested (with non-zero values
|
||||
* in both the stack and stacksize args), set up the user stack pointer
|
||||
* accordingly.
|
||||
* in both the stack and stacksize args), set up the user stack
|
||||
* pointer accordingly.
|
||||
*/
|
||||
void
|
||||
cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack,
|
||||
size_t stacksize, void (*func)(void *), void *arg)
|
||||
{
|
||||
struct switchframe *sf;
|
||||
|
||||
#if 0 /* FIXME: probably wrong for yamt-idlelwp */
|
||||
KDASSERT(l1 == curlwp || l1 == &lwp0);
|
||||
#endif
|
||||
|
||||
sh3_setup_uarea(l2);
|
||||
|
||||
l2->l_md.md_flags = l1->l_md.md_flags;
|
||||
l2->l_md.md_astpending = 0;
|
||||
|
||||
/* Copy user context, may be give a different stack */
|
||||
memcpy(l2->l_md.md_regs, l1->l_md.md_regs, sizeof(struct trapframe));
|
||||
if (stack != NULL)
|
||||
l2->l_md.md_regs->tf_r15 = (u_int)stack + stacksize;
|
||||
|
||||
/* When l2 is switched to, jump to the trampoline */
|
||||
sf = &l2->l_md.md_pcb->pcb_sf;
|
||||
sf->sf_pr = (int)lwp_trampoline;
|
||||
sf->sf_r10 = (int)l2; /* "new" lwp for lwp_startup() */
|
||||
sf->sf_r11 = (int)arg; /* hook function/argument */
|
||||
sf->sf_r12 = (int)func;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reset the stack pointer for the lwp and arrange for it to call the
|
||||
* specified function with the specified argument on next switch.
|
||||
*
|
||||
* XXX: Scheduler activations relics! Not used anymore but keep
|
||||
* around for reference in case we gonna revive SA.
|
||||
*/
|
||||
void
|
||||
cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg)
|
||||
{
|
||||
struct switchframe *sf;
|
||||
|
||||
sh3_setup_uarea(l);
|
||||
|
||||
l->l_md.md_regs->tf_ssr = PSL_USERSET;
|
||||
|
||||
/* When lwp is switched to, jump to the trampoline */
|
||||
sf = &l->l_md.md_pcb->pcb_sf;
|
||||
sf->sf_pr = (int)lwp_setfunc_trampoline;
|
||||
sf->sf_r11 = (int)arg; /* hook function/argument */
|
||||
sf->sf_r12 = (int)func;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sh3_setup_uarea(struct lwp *l)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
struct trapframe *tf;
|
||||
|
@ -136,134 +191,27 @@ cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack,
|
|||
vaddr_t spbase, fptop;
|
||||
#define P1ADDR(x) (SH3_PHYS_TO_P1SEG(*__pmap_kpte_lookup(x) & PG_PPN))
|
||||
|
||||
#if 0 /* FIXME: probably wrong for yamt-idlelwp */
|
||||
KDASSERT(l1 == curlwp || l1 == &lwp0);
|
||||
#endif
|
||||
|
||||
/* Copy flags */
|
||||
l2->l_md.md_flags = l1->l_md.md_flags;
|
||||
l2->l_md.md_astpending = 0;
|
||||
|
||||
pcb = NULL; /* XXXGCC: -Wuninitialized */
|
||||
pcb = &l->l_addr->u_pcb;
|
||||
#ifdef SH3
|
||||
/*
|
||||
* Convert frame pointer top to P1. because SH3 can't make
|
||||
* wired TLB entry, context store space accessing must not cause
|
||||
* exception. For SH3, we are 4K page, P3/P1 conversion don't
|
||||
* cause virtual-aliasing.
|
||||
* Accessing context store space must not cause exceptions.
|
||||
* SH4 can make wired TLB entries so P3 address for PCB is ok.
|
||||
* SH3 cannot, so we need to convert to P1. P3/P1 conversion
|
||||
* doesn't cause virtual-aliasing.
|
||||
*/
|
||||
if (CPU_IS_SH3)
|
||||
pcb = (struct pcb *)P1ADDR((vaddr_t)&l2->l_addr->u_pcb);
|
||||
pcb = (struct pcb *)P1ADDR((vaddr_t)pcb);
|
||||
#endif /* SH3 */
|
||||
#ifdef SH4
|
||||
/* SH4 can make wired entry, no need to convert to P1. */
|
||||
if (CPU_IS_SH4)
|
||||
pcb = &l2->l_addr->u_pcb;
|
||||
#endif /* SH4 */
|
||||
|
||||
l2->l_md.md_pcb = pcb;
|
||||
fptop = (vaddr_t)pcb + PAGE_SIZE;
|
||||
|
||||
/* set up the kernel stack pointer */
|
||||
spbase = (vaddr_t)l2->l_addr + PAGE_SIZE;
|
||||
#ifdef P1_STACK
|
||||
/* Convert to P1 from P3 */
|
||||
/*
|
||||
* wbinv u-area to avoid cache-aliasing, since kernel stack
|
||||
* is accessed from P1 instead of P3.
|
||||
*/
|
||||
if (SH_HAS_VIRTUAL_ALIAS)
|
||||
sh_dcache_wbinv_range((vaddr_t)l2->l_addr, USPACE);
|
||||
spbase = P1ADDR(spbase);
|
||||
#else /* !P1_STACK */
|
||||
/* Prepare u-area PTEs */
|
||||
#ifdef SH3
|
||||
if (CPU_IS_SH3)
|
||||
sh3_switch_setup(l2);
|
||||
#endif
|
||||
#ifdef SH4
|
||||
if (CPU_IS_SH4)
|
||||
sh4_switch_setup(l2);
|
||||
#endif
|
||||
#endif /* !P1_STACK */
|
||||
|
||||
#ifdef KSTACK_DEBUG
|
||||
/* Fill magic number for tracking */
|
||||
memset((char *)fptop - PAGE_SIZE + sizeof(struct user), 0x5a,
|
||||
PAGE_SIZE - sizeof(struct user));
|
||||
memset((char *)spbase, 0xa5, (USPACE - PAGE_SIZE));
|
||||
memset(&pcb->pcb_sf, 0xb4, sizeof(struct switchframe));
|
||||
#endif /* KSTACK_DEBUG */
|
||||
|
||||
/*
|
||||
* Copy the user context.
|
||||
*/
|
||||
l2->l_md.md_regs = tf = (struct trapframe *)fptop - 1;
|
||||
memcpy(tf, l1->l_md.md_regs, sizeof(struct trapframe));
|
||||
|
||||
/*
|
||||
* If specified, give the child a different stack.
|
||||
*/
|
||||
if (stack != NULL)
|
||||
tf->tf_r15 = (u_int)stack + stacksize;
|
||||
|
||||
/* Setup switch frame */
|
||||
sf = &pcb->pcb_sf;
|
||||
sf->sf_r10 = (int)l2; /* "new" for lwp_startup */
|
||||
sf->sf_r11 = (int)arg; /* lwp_trampoline hook func */
|
||||
sf->sf_r12 = (int)func; /* lwp_trampoline hook func's arg */
|
||||
sf->sf_r15 = spbase + USPACE - PAGE_SIZE;/* current stack pointer */
|
||||
sf->sf_r7_bank = sf->sf_r15; /* stack top */
|
||||
sf->sf_r6_bank = (vaddr_t)tf; /* current frame pointer */
|
||||
/* when switch to me, jump to lwp_trampoline */
|
||||
sf->sf_pr = (int)lwp_trampoline;
|
||||
/*
|
||||
* Enable interrupt when switch frame is restored, since
|
||||
* kernel thread begin to run without restoring trapframe.
|
||||
*/
|
||||
sf->sf_sr = PSL_MD; /* kernel mode, interrupt enable */
|
||||
}
|
||||
|
||||
/*
|
||||
* void cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg):
|
||||
* + Reset the stack pointer for the process.
|
||||
* + Arrange to the process to call the specified func
|
||||
* with argument via the lwp_setfunc_trampoline.
|
||||
*
|
||||
* XXX There is a lot of duplicated code here (with cpu_lwp_fork()).
|
||||
*/
|
||||
void
|
||||
cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg)
|
||||
{
|
||||
struct pcb *pcb;
|
||||
struct trapframe *tf;
|
||||
struct switchframe *sf;
|
||||
vaddr_t fptop, spbase;
|
||||
|
||||
pcb = NULL; /* XXXGCC: -Wuninitialized */
|
||||
#ifdef SH3
|
||||
/*
|
||||
* Convert frame pointer top to P1. because SH3 can't make
|
||||
* wired TLB entry, context store space accessing must not cause
|
||||
* exception. For SH3, we are 4K page, P3/P1 conversion don't
|
||||
* cause virtual-aliasing.
|
||||
*/
|
||||
if (CPU_IS_SH3)
|
||||
pcb = (struct pcb *)P1ADDR((vaddr_t)&l->l_addr->u_pcb);
|
||||
#endif /* SH3 */
|
||||
#ifdef SH4
|
||||
/* SH4 can make wired entry, no need to convert to P1. */
|
||||
if (CPU_IS_SH4)
|
||||
pcb = &l->l_addr->u_pcb;
|
||||
#endif /* SH4 */
|
||||
|
||||
fptop = (vaddr_t)pcb + PAGE_SIZE;
|
||||
l->l_md.md_pcb = pcb;
|
||||
|
||||
/* stack for trapframes */
|
||||
fptop = (vaddr_t)pcb + PAGE_SIZE;
|
||||
tf = (struct trapframe *)fptop - 1;
|
||||
l->l_md.md_regs = tf;
|
||||
|
||||
/* set up the kernel stack pointer */
|
||||
spbase = (vaddr_t)l->l_addr + PAGE_SIZE;
|
||||
#ifdef P1_STACK
|
||||
/* Convert to P1 from P3 */
|
||||
/*
|
||||
* wbinv u-area to avoid cache-aliasing, since kernel stack
|
||||
* is accessed from P1 instead of P3.
|
||||
|
@ -291,25 +239,20 @@ cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg)
|
|||
memset(&pcb->pcb_sf, 0xb4, sizeof(struct switchframe));
|
||||
#endif /* KSTACK_DEBUG */
|
||||
|
||||
l->l_md.md_regs = tf = (struct trapframe *)fptop - 1;
|
||||
tf->tf_ssr = PSL_USERSET;
|
||||
|
||||
/* Setup switch frame */
|
||||
/* Setup kernel stack and trapframe stack */
|
||||
sf = &pcb->pcb_sf;
|
||||
sf->sf_r11 = (int)arg; /* lwp_setfunc_trampoline hook func */
|
||||
sf->sf_r12 = (int)func; /* lwp_setfunc_trampoline hook func's arg */
|
||||
sf->sf_r15 = spbase + USPACE - PAGE_SIZE;/* current stack pointer */
|
||||
sf->sf_r7_bank = sf->sf_r15; /* stack top */
|
||||
sf->sf_r6_bank = (vaddr_t)tf; /* current frame pointer */
|
||||
/* when switch to me, jump to lwp_setfunc_trampoline */
|
||||
sf->sf_pr = (int)lwp_setfunc_trampoline;
|
||||
sf->sf_r6_bank = (vaddr_t)tf;
|
||||
sf->sf_r7_bank = spbase + USPACE - PAGE_SIZE;
|
||||
sf->sf_r15 = sf->sf_r7_bank;
|
||||
|
||||
/*
|
||||
* Enable interrupt when switch frame is restored, since
|
||||
* kernel thread begin to run without restoring trapframe.
|
||||
* Enable interrupts when switch frame is restored, since
|
||||
* kernel thread begins to run without restoring trapframe.
|
||||
*/
|
||||
sf->sf_sr = PSL_MD; /* kernel mode, interrupt enable */
|
||||
sf->sf_sr = PSL_MD; /* kernel mode, interrupt enable */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cpu_lwp_free(struct lwp *l, int proc)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue