Add a new field 'md_kernnest' to the alpha machine dependent process

structure.  This field keeps track of how many levels deep we are nested
into the kernel.  The nesting level is bumped at the start of a trap,
interrupt, syscall, or exception and is decremented on return.  This is
used to detect the case when the kernel is returning back to a kernel
context in exception_return().  If we are returning to the kernel we need
to update the globaldata pointer register saved in the stack frame in case
we have switched CPU's between taking the initial interrupt that saved the
frame and returning.  If we don't do this fixup it is possible for a CPU to
use the wrong per-cpu data.  On UP systems this is not a problem, so the
code is conditional on SMP.

A count was used instead of simply checking the process status register in
the frame during exception_return() since there are critical sections at
the very start and end of a trap, exception, or interrupt from userland in
which we could trash the t7 register being used in userland.  The counter
is incremented after adn before these critical sections respectively so
that we will not overwrite the saved t7 register if we are interrupted
during one of these critical sections.
This commit is contained in:
John Baldwin 2001-04-24 21:06:53 +00:00
parent a483f58aea
commit 9e438eb4f5
7 changed files with 72 additions and 15 deletions

View file

@ -140,16 +140,19 @@ XentSys1: LDGP(pv)
beq t1, exception_return
/* set the hae register if this process has specified a value */
ldq t0, GD_CURPROC(globalp)
beq t0, 3f
ldq t1, P_MD_FLAGS(t0)
ldq s0, GD_CURPROC(globalp)
ldq t1, P_MD_FLAGS(s0)
and t1, MDP_HAEUSED
beq t1, 3f
ldq a0, P_MD_HAE(t0)
ldq a0, P_MD_HAE(s0)
ldq pv, chipset + CHIPSET_WRITE_HAE
CALL((pv))
3:
#ifdef SMP
/* leave the kernel */
stl zero, P_MD_KERNNEST(s0)
#endif
/* restore the registers, and return */
ldq v0,(FRAME_V0*8)(sp)
ldq s0,(FRAME_S0*8)(sp)
@ -253,28 +256,42 @@ LEAF(exception_return, 1) /* XXX should be NESTED */
br pv, Ler1
Ler1: LDGP(pv)
ldq s1, (FRAME_PS * 8)(sp) /* get the saved PS */
and s1, ALPHA_PSL_IPL_MASK, t0 /* look at the saved IPL */
bne t0, Lrestoreregs /* != 0: can't do AST or SIR */
ldq s0, GD_CURPROC(globalp) /* save curproc in s0 */
#ifdef SMP
ldl s1, P_MD_KERNNEST(s0)
subl s1, 1, s1 /* decrement nesting level */
#endif
and s1, ALPHA_PSL_USERMODE, t0 /* are we returning to user? */
beq t0, Lrestoreregs /* no: just return */
ldq t1, (FRAME_PS * 8)(sp) /* get the saved PS */
and t1, ALPHA_PSL_USERMODE, t0 /* are we returning to user? */
beq t0, Lkernelret /* no: kernel return */
/* Handle any AST's or resched's. */
mov sp, a0 /* only arg is frame */
CALL(ast)
#ifdef SMP
br Lrestoreregs
#endif
Lkernelret:
#ifdef SMP
beq s1, Lrestoreregs
stq globalp, (FRAME_T7*8)(sp) /* fixup globalp */
#endif
Lrestoreregs:
/* set the hae register if this process has specified a value */
ldq t0, GD_CURPROC(globalp)
beq t0, Lnohae
ldq t1, P_MD_FLAGS(t0)
ldq t1, P_MD_FLAGS(s0)
and t1, MDP_HAEUSED
beq t1, Lnohae
ldq a0, P_MD_HAE(t0)
ldq pv, chipset + CHIPSET_WRITE_HAE
CALL((pv))
Lnohae:
#ifdef SMP
/* leave the kernel */
stl s1, P_MD_KERNNEST(s0)
#endif
/* restore the registers, and return */
bsr ra, exception_restore_regs /* jmp/CALL trashes pv/t12 */

View file

@ -84,6 +84,9 @@ ASSYM(P_ADDR, offsetof(struct proc, p_addr));
ASSYM(P_MD_FLAGS, offsetof(struct proc, p_md.md_flags));
ASSYM(P_MD_PCBPADDR, offsetof(struct proc, p_md.md_pcbpaddr));
ASSYM(P_MD_HAE, offsetof(struct proc, p_md.md_hae));
#ifdef SMP
ASSYM(P_MD_KERNNEST, offsetof(struct proc, p_md.md_kernnest));
#endif
ASSYM(MDP_HAEUSED, MDP_HAEUSED);
ASSYM(CHIPSET_WRITE_HAE, offsetof(struct alpha_chipset, write_hae));

View file

@ -91,12 +91,22 @@ interrupt(a0, a1, a2, framep)
struct trapframe *framep;
{
struct proc *p;
#ifdef SMP
critical_t s;
#endif
/*
* Find our per-cpu globals.
*/
#ifdef SMP
s = critical_enter();
#endif
globalp = (struct globaldata *) alpha_pal_rdval();
p = curproc;
#ifdef SMP
p->p_md.md_kernnest++;
critical_exit(s);
#endif
atomic_add_int(&p->p_intr_nesting_level, 1);
#ifndef SMP
{

View file

@ -966,6 +966,9 @@ alpha_init(pfn, ptb, bim, bip, biv)
globaldata_init(globalp, alpha_pal_whami(), sz);
alpha_pal_wrval((u_int64_t) globalp);
PCPU_GET(next_asn) = 1; /* 0 used for proc0 pmap */
#ifdef SMP
proc0.p_md.md_kernnest = 1;
#endif
}
/*

View file

@ -312,14 +312,24 @@ trap(a0, a1, a2, entry, framep)
u_int64_t ucode;
u_quad_t sticks;
int user;
#ifdef SMP
critical_t s;
#endif
/*
* Find our per-cpu globals.
*/
#ifdef SMP
s = critical_enter();
#endif
globalp = (struct globaldata *) alpha_pal_rdval();
p = curproc;
#ifdef SMP
p->p_md.md_kernnest++;
critical_exit(s);
#endif
cnt.v_trap++;
p = curproc;
ucode = 0;
user = (framep->tf_regs[FRAME_PS] & ALPHA_PSL_USERMODE) != 0;
if (user) {
@ -704,11 +714,22 @@ syscall(code, framep)
u_quad_t sticks;
u_int64_t args[10]; /* XXX */
u_int hidden = 0, nargs;
#ifdef SMP
critical_t s;
#endif
/*
* Find our per-cpu globals.
*/
#ifdef SMP
s = critical_enter();
#endif
globalp = (struct globaldata *) alpha_pal_rdval();
p = curproc;
#ifdef SMP
p->p_md.md_kernnest++;
critical_exit(s);
#endif
mtx_lock(&Giant);
framep->tf_regs[FRAME_TRAPARG_A0] = 0;
@ -720,7 +741,6 @@ syscall(code, framep)
#endif
cnt.v_syscall++;
p = curproc;
p->p_md.md_tf = framep;
opc = framep->tf_regs[FRAME_PC] - 4;
mtx_lock_spin(&sched_lock);

View file

@ -50,6 +50,7 @@ struct mdproc {
struct mdbpt md_sstep[2]; /* two single step breakpoints */
u_int64_t md_hae; /* user HAE register value */
void *osf_sigtramp; /* user-level signal trampoline */
u_int md_kernnest; /* nesting level in the kernel */
};
#define MDP_FPUSED 0x0001 /* Process used the FPU */

View file

@ -84,6 +84,9 @@ ASSYM(P_ADDR, offsetof(struct proc, p_addr));
ASSYM(P_MD_FLAGS, offsetof(struct proc, p_md.md_flags));
ASSYM(P_MD_PCBPADDR, offsetof(struct proc, p_md.md_pcbpaddr));
ASSYM(P_MD_HAE, offsetof(struct proc, p_md.md_hae));
#ifdef SMP
ASSYM(P_MD_KERNNEST, offsetof(struct proc, p_md.md_kernnest));
#endif
ASSYM(MDP_HAEUSED, MDP_HAEUSED);
ASSYM(CHIPSET_WRITE_HAE, offsetof(struct alpha_chipset, write_hae));