From 9e438eb4f52d6a5c36c097f5dfd08a9cf10df772 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Tue, 24 Apr 2001 21:06:53 +0000 Subject: [PATCH] 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. --- sys/alpha/alpha/exception.s | 43 ++++++++++++++++++++++++---------- sys/alpha/alpha/genassym.c | 3 +++ sys/alpha/alpha/interrupt.c | 10 ++++++++ sys/alpha/alpha/machdep.c | 3 +++ sys/alpha/alpha/trap.c | 24 +++++++++++++++++-- sys/alpha/include/proc.h | 1 + sys/powerpc/powerpc/genassym.c | 3 +++ 7 files changed, 72 insertions(+), 15 deletions(-) diff --git a/sys/alpha/alpha/exception.s b/sys/alpha/alpha/exception.s index bc8ee5730df..b3bf1dceab4 100644 --- a/sys/alpha/alpha/exception.s +++ b/sys/alpha/alpha/exception.s @@ -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 */ diff --git a/sys/alpha/alpha/genassym.c b/sys/alpha/alpha/genassym.c index 51046549ce3..03990ea51b3 100644 --- a/sys/alpha/alpha/genassym.c +++ b/sys/alpha/alpha/genassym.c @@ -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)); diff --git a/sys/alpha/alpha/interrupt.c b/sys/alpha/alpha/interrupt.c index c44eccf3b13..346b21cd544 100644 --- a/sys/alpha/alpha/interrupt.c +++ b/sys/alpha/alpha/interrupt.c @@ -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 { diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c index 78036218e1d..f6236690593 100644 --- a/sys/alpha/alpha/machdep.c +++ b/sys/alpha/alpha/machdep.c @@ -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 } /* diff --git a/sys/alpha/alpha/trap.c b/sys/alpha/alpha/trap.c index 1b08a7d128b..228c50b81bb 100644 --- a/sys/alpha/alpha/trap.c +++ b/sys/alpha/alpha/trap.c @@ -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); diff --git a/sys/alpha/include/proc.h b/sys/alpha/include/proc.h index d003816ab0b..3a83c3942f7 100644 --- a/sys/alpha/include/proc.h +++ b/sys/alpha/include/proc.h @@ -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 */ diff --git a/sys/powerpc/powerpc/genassym.c b/sys/powerpc/powerpc/genassym.c index 51046549ce3..03990ea51b3 100644 --- a/sys/powerpc/powerpc/genassym.c +++ b/sys/powerpc/powerpc/genassym.c @@ -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));