New version of cpu_switch/switchexit, mostly to simplify SMP support. It's
currently conditional on ALT_SWITCH_CODE (defaults to `on' if MULTIPROCESSOR is defined) until more testing rounds are completed.
This commit is contained in:
parent
3d8def4865
commit
7b7269ba42
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: locore.s,v 1.172 2002/12/31 14:34:54 pk Exp $ */
|
||||
/* $NetBSD: locore.s,v 1.173 2002/12/31 16:17:12 pk Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 Paul Kranenburg
|
||||
|
@ -67,11 +67,15 @@
|
|||
#include <sparc/dev/zsreg.h>
|
||||
#endif
|
||||
#include <machine/ctlreg.h>
|
||||
#include <machine/intr.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/signal.h>
|
||||
#include <machine/trap.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#ifdef MULTIPROCESSOR
|
||||
#define ALT_SWITCH_CODE 1
|
||||
#endif
|
||||
/*
|
||||
* GNU assembler does not understand `.empty' directive; Sun assembler
|
||||
* gripes about labels without it. To allow cross-compilation using
|
||||
|
@ -364,6 +368,18 @@ sun4_notsup:
|
|||
#define ZS_INTERRUPT4M HARDINT4M(12)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define TRAP_TRACE(tt, tmp) \
|
||||
sethi %hi(CPUINFO_VA + CPUINFO_TT), tmp; \
|
||||
st tt, [tmp + %lo(CPUINFO_VA + CPUINFO_TT)];
|
||||
#define TRAP_TRACE2(tt, tmp1, tmp2) \
|
||||
mov tt, tmp1; \
|
||||
TRAP_TRACE(tmp1, tmp2)
|
||||
#else /* DEBUG */
|
||||
#define TRAP_TRACE(tt,tmp) /**/
|
||||
#define TRAP_TRACE2(tt,tmp1,tmp2) /**/
|
||||
#endif /* DEBUG */
|
||||
|
||||
.globl _ASM_LABEL(start), _C_LABEL(kernel_text)
|
||||
_C_LABEL(kernel_text) = start ! for kvm_mkdb(8)
|
||||
_ASM_LABEL(start):
|
||||
|
@ -1163,7 +1179,8 @@ trapbase_sun4m:
|
|||
.skip 4096
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
/* redzones don't work currently in multi-processor mode */
|
||||
#if defined(DEBUG) && !defined(MULTIPROCESSOR)
|
||||
/*
|
||||
* A hardware red zone is impossible. We simulate one in software by
|
||||
* keeping a `red zone' pointer; if %sp becomes less than this, we panic.
|
||||
|
@ -1467,6 +1484,7 @@ wmask: .skip 32 ! u_char wmask[0..31];
|
|||
mov %g7, %l7 /* save %g7 in %l7 for clean_trap_window */
|
||||
|
||||
#define TRAP_SETUP(stackspace) \
|
||||
TRAP_TRACE(%l3,%l5); \
|
||||
rd %wim, %l4; \
|
||||
mov 1, %l5; \
|
||||
sll %l5, %l0, %l5; \
|
||||
|
@ -1517,6 +1535,7 @@ wmask: .skip 32 ! u_char wmask[0..31];
|
|||
* to check the current %fp against both ends of the stack space.
|
||||
*/
|
||||
#define INTR_SETUP(stackspace) \
|
||||
TRAP_TRACE(%l3,%l5); \
|
||||
rd %wim, %l4; \
|
||||
mov 1, %l5; \
|
||||
sll %l5, %l0, %l5; \
|
||||
|
@ -1567,6 +1586,7 @@ wmask: .skip 32 ! u_char wmask[0..31];
|
|||
#else /* MULTIPROCESSOR */
|
||||
|
||||
#define INTR_SETUP(stackspace) \
|
||||
TRAP_TRACE(%l3,%l5); \
|
||||
rd %wim, %l4; \
|
||||
mov 1, %l5; \
|
||||
sll %l5, %l0, %l5; \
|
||||
|
@ -2126,8 +2146,8 @@ softtrap:
|
|||
* The interrupt stack is not at a fixed location
|
||||
* and %sp must be checked against both ends.
|
||||
*/
|
||||
sethi %hi(_EINTSTACKP), %l7
|
||||
ld [%l7 + %lo(_EINTSTACKP)], %l7
|
||||
sethi %hi(_EINTSTACKP), %l6
|
||||
ld [%l6 + %lo(_EINTSTACKP)], %l7
|
||||
cmp %sp, %l7
|
||||
bge Lslowtrap_reenter
|
||||
EMPTY
|
||||
|
@ -2333,6 +2353,10 @@ kgdb_rett:
|
|||
*/
|
||||
_C_LABEL(_syscall):
|
||||
TRAP_SETUP(-CCFSZ-80)
|
||||
#ifdef DEBUG
|
||||
or %g1, 0x1000, %l6 ! mark syscall
|
||||
TRAP_TRACE(%l6,%l5)
|
||||
#endif
|
||||
wr %l0, PSR_ET, %psr
|
||||
std %l0, [%sp + CCFSZ + 0] ! tf_psr, tf_pc
|
||||
rd %y, %l3
|
||||
|
@ -2599,7 +2623,7 @@ sparc_interrupt_common:
|
|||
ld [%l4 + %l5], %l4
|
||||
|
||||
#if defined(MULTIPROCESSOR) && defined(SUN4M) /* XXX */
|
||||
cmp %l3, PIL_SCHED
|
||||
cmp %l3, IPL_SCHED
|
||||
bgu 0f
|
||||
nop
|
||||
call _C_LABEL(intr_lock_kernel)
|
||||
|
@ -2641,7 +2665,7 @@ sparc_interrupt_common:
|
|||
/* all done: restore registers and go return */
|
||||
4:
|
||||
#if defined(MULTIPROCESSOR) && defined(SUN4M) /* XXX */
|
||||
cmp %l3, PIL_SCHED
|
||||
cmp %l3, IPL_SCHED
|
||||
bgu 0f
|
||||
nop
|
||||
call _C_LABEL(intr_unlock_kernel)
|
||||
|
@ -2913,6 +2937,7 @@ window_of:
|
|||
* a lot of time, so we have separate paths for kernel and user.
|
||||
* We also know for sure that the window has overflowed.
|
||||
*/
|
||||
TRAP_TRACE2(5,%l6,%l5)
|
||||
btst PSR_PS, %l0
|
||||
bz winof_user
|
||||
sethi %hi(clean_trap_window), %l7
|
||||
|
@ -3010,6 +3035,7 @@ window_uf:
|
|||
save %g0, %g0, %g0 ! back to T
|
||||
RETT
|
||||
#else
|
||||
TRAP_TRACE2(6,%l6,%l5)
|
||||
wr %g0, 0, %wim ! allow us to enter I
|
||||
btst PSR_PS, %l0
|
||||
restore ! enter window R
|
||||
|
@ -3984,6 +4010,7 @@ startmap_done:
|
|||
* The save/restore code has 7 "save"'s followed by 7
|
||||
* "restore"'s -- we "nop" out the last "save" and first
|
||||
* "restore"
|
||||
* ALT_SWITCH_CODE: there are 6 saves/restores
|
||||
*/
|
||||
cmp %o0, 8
|
||||
be 1f
|
||||
|
@ -3991,8 +4018,13 @@ noplab: nop
|
|||
sethi %hi(noplab), %l0
|
||||
ld [%l0 + %lo(noplab)], %l1
|
||||
set wb1, %l0
|
||||
#if ALT_SWITCH_CODE
|
||||
st %l1, [%l0 + 5*4]
|
||||
st %l1, [%l0 + 6*4]
|
||||
#else
|
||||
st %l1, [%l0 + 6*4]
|
||||
st %l1, [%l0 + 7*4]
|
||||
#endif
|
||||
1:
|
||||
#endif
|
||||
|
||||
|
@ -4224,8 +4256,15 @@ _C_LABEL(cpu_hatch):
|
|||
ld [%l1], %l0
|
||||
|
||||
#if 0 /* doesn't quite work yet */
|
||||
|
||||
set _C_LABEL(proc0), %g3 ! p = proc0
|
||||
#if ALT_SWITCH_CODE
|
||||
mov PSR_S|PSR_ET, %l1 ! oldpsr = PSR_S | PSR_ET;
|
||||
sethi %hi(_C_LABEL(sched_whichqs)), %l2
|
||||
clr %l4
|
||||
sethi %hi(cpcb), %l6
|
||||
b idle_enter
|
||||
sethi %hi(curproc), %l7
|
||||
#else /* ALT_SWITCH_CODE */
|
||||
!set _C_LABEL(proc0), %g3 ! p = proc0
|
||||
sethi %hi(_C_LABEL(sched_whichqs)), %g2
|
||||
sethi %hi(cpcb), %g6
|
||||
sethi %hi(curproc), %g7
|
||||
|
@ -4245,6 +4284,7 @@ _C_LABEL(cpu_hatch):
|
|||
|
||||
b idle_enter_no_schedlock
|
||||
clr %g4 ! lastproc = NULL;
|
||||
#endif /* ALT_SWITCH_CODE */
|
||||
#else
|
||||
/* Idle here .. */
|
||||
9: ba 9b
|
||||
|
@ -4513,6 +4553,520 @@ ENTRY(write_user_windows)
|
|||
.comm _C_LABEL(nswitchdiff), 4
|
||||
.comm _C_LABEL(nswitchexit), 4
|
||||
|
||||
#if ALT_SWITCH_CODE
|
||||
/*
|
||||
* switchexit is called only from cpu_exit() before the current process
|
||||
* has freed its vmspace and kernel stack; we must schedule them to be
|
||||
* freed. (curproc is already NULL.)
|
||||
*
|
||||
* We lay the process to rest by changing to the `idle' kernel stack,
|
||||
* and note that the `last loaded process' is nonexistent.
|
||||
*/
|
||||
ENTRY(switchexit)
|
||||
mov %o0, %g2 ! save proc for exit2() call
|
||||
|
||||
/*
|
||||
* Change pcb to idle u. area, i.e., set %sp to top of stack
|
||||
* and %psr to PSR_S|PSR_ET, and set cpcb to point to idle_u.
|
||||
* Once we have left the old stack, we can call exit2() to
|
||||
* destroy it. Call it any sooner and the register windows
|
||||
* go bye-bye.
|
||||
*/
|
||||
#if defined(MULTIPROCESSOR)
|
||||
sethi %hi(IDLE_UP), %g5
|
||||
ld [%g5 + %lo(IDLE_UP)], %g5
|
||||
#else
|
||||
set _C_LABEL(idle_u), %g5
|
||||
#endif
|
||||
sethi %hi(cpcb), %g6
|
||||
mov 1, %g7
|
||||
wr %g0, PSR_S, %psr ! change to window 0, traps off
|
||||
wr %g0, 2, %wim ! and make window 1 the trap window
|
||||
st %g5, [%g6 + %lo(cpcb)] ! cpcb = &idle_u
|
||||
st %g7, [%g5 + PCB_WIM] ! idle_u.pcb_wim = log2(2) = 1
|
||||
#if defined(MULTIPROCESSOR)
|
||||
set USPACE-CCFSZ, %o1 !
|
||||
add %g5, %o1, %sp ! set new %sp
|
||||
#else
|
||||
set _C_LABEL(idle_u) + USPACE-CCFSZ, %sp ! set new %sp
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
mov %g5, %l6 ! %l6 = _idle_u
|
||||
SET_SP_REDZONE(%l6, %l5)
|
||||
#endif
|
||||
wr %g0, PSR_S|PSR_ET, %psr ! and then enable traps
|
||||
call _C_LABEL(exit2) ! exit2(p)
|
||||
mov %g2, %o0
|
||||
|
||||
/*
|
||||
* Now fall through to `the last switch'. %l6 was set to
|
||||
* %hi(cpcb), but may have been clobbered in exit2(),
|
||||
* so all the registers described below will be set here.
|
||||
*
|
||||
* REGISTER USAGE AT THIS POINT:
|
||||
* %l1 = oldpsr (excluding ipl bits)
|
||||
* %l2 = %hi(whichqs)
|
||||
* %l4 = lastproc
|
||||
* %l6 = %hi(cpcb)
|
||||
* %l7 = %hi(curproc)
|
||||
* %o0 = tmp 1
|
||||
* %o1 = tmp 2
|
||||
*/
|
||||
|
||||
INCR(_C_LABEL(nswitchexit)) ! nswitchexit++;
|
||||
INCR(_C_LABEL(uvmexp)+V_SWTCH) ! cnt.v_switch++;
|
||||
|
||||
mov PSR_S|PSR_ET, %l1 ! oldpsr = PSR_S | PSR_ET;
|
||||
sethi %hi(_C_LABEL(sched_whichqs)), %l2
|
||||
clr %l4 ! lastproc = NULL;
|
||||
sethi %hi(cpcb), %l6
|
||||
sethi %hi(curproc), %l7
|
||||
b idle_enter
|
||||
st %g0, [%l7 + %lo(curproc)] ! curproc = NULL;
|
||||
|
||||
/*
|
||||
* When no processes are on the runq, switch
|
||||
* idles here waiting for something to come ready.
|
||||
* The registers are set up as noted above.
|
||||
*/
|
||||
idle:
|
||||
#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
|
||||
! unlock scheduler lock
|
||||
call _C_LABEL(sched_unlock_idle)
|
||||
nop
|
||||
#endif
|
||||
|
||||
idle_enter:
|
||||
wr %l1, 0, %psr ! (void) spl0();
|
||||
1: ! spin reading whichqs until nonzero
|
||||
ld [%l2 + %lo(_C_LABEL(sched_whichqs))], %o3
|
||||
tst %o3
|
||||
#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
|
||||
bnz,a idle_leave
|
||||
#else
|
||||
bnz,a Lsw_scan
|
||||
#endif
|
||||
! NB: annulled delay slot (executed when we leave the idle loop)
|
||||
wr %l1, (IPL_SCHED << 8), %psr ! (void) splsched();
|
||||
|
||||
! Check uvm.page_idle_zero
|
||||
sethi %hi(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO), %o3
|
||||
ld [%o3 + %lo(_C_LABEL(uvm) + UVM_PAGE_IDLE_ZERO)], %o3
|
||||
tst %o3
|
||||
bz 1b
|
||||
nop
|
||||
|
||||
call _C_LABEL(uvm_pageidlezero)
|
||||
nop
|
||||
b,a 1b
|
||||
|
||||
#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
|
||||
idle_leave:
|
||||
/* Before we leave the idle loop, detain the scheduler lock */
|
||||
nop;nop;nop; ! just wrote to %psr; delay before doing a `save'
|
||||
call _C_LABEL(sched_lock_idle)
|
||||
nop
|
||||
b,a Lsw_scan
|
||||
#endif
|
||||
|
||||
Lsw_panic_rq:
|
||||
sethi %hi(1f), %o0
|
||||
call _C_LABEL(panic)
|
||||
or %lo(1f), %o0, %o0
|
||||
Lsw_panic_wchan:
|
||||
sethi %hi(2f), %o0
|
||||
call _C_LABEL(panic)
|
||||
or %lo(2f), %o0, %o0
|
||||
Lsw_panic_srun:
|
||||
sethi %hi(3f), %o0
|
||||
call _C_LABEL(panic)
|
||||
or %lo(3f), %o0, %o0
|
||||
1: .asciz "switch rq"
|
||||
2: .asciz "switch wchan"
|
||||
3: .asciz "switch SRUN"
|
||||
_ALIGN
|
||||
|
||||
/*
|
||||
* cpu_switch() picks a process to run and runs it, saving the current
|
||||
* one away. On the assumption that (since most workstations are
|
||||
* single user machines) the chances are quite good that the new
|
||||
* process will turn out to be the current process, we defer saving
|
||||
* it here until we have found someone to load. If that someone
|
||||
* is the current process we avoid both store and load.
|
||||
*
|
||||
* cpu_switch() is always entered at splsched.
|
||||
*
|
||||
* IT MIGHT BE WORTH SAVING BEFORE ENTERING idle TO AVOID HAVING TO
|
||||
* SAVE LATER WHEN SOMEONE ELSE IS READY ... MUST MEASURE!
|
||||
*/
|
||||
.globl _C_LABEL(__ffstab)
|
||||
ENTRY(cpu_switch)
|
||||
ENTRY(cpu_switchto)
|
||||
/*
|
||||
* REGISTER USAGE AT THIS POINT:
|
||||
* %l1 = oldpsr (excluding ipl bits)
|
||||
* %l2 = %hi(whichqs)
|
||||
* %l3(%g3) = p
|
||||
* %l4(%g4) = lastproc
|
||||
* %l5 = tmp 0
|
||||
* %l6 = %hi(cpcb)
|
||||
* %l7 = %hi(curproc)
|
||||
* %o0 = tmp 1
|
||||
* %o1 = tmp 2
|
||||
* %o2 = tmp 3
|
||||
* %o3 = tmp 4, then at Lsw_scan, whichqs
|
||||
* %o4 = tmp 5, then at Lsw_scan, which
|
||||
* %o5 = tmp 6, then at Lsw_scan, q
|
||||
*/
|
||||
save %sp, -CCFSZ, %sp
|
||||
mov %i0, %l4 ! save p
|
||||
sethi %hi(cpcb), %l6
|
||||
ld [%l6 + %lo(cpcb)], %o0
|
||||
std %i6, [%o0 + PCB_SP] ! cpcb->pcb_<sp,pc> = <fp,pc>;
|
||||
rd %psr, %l1 ! oldpsr = %psr;
|
||||
sethi %hi(curproc), %l7
|
||||
st %l1, [%o0 + PCB_PSR] ! cpcb->pcb_psr = oldpsr;
|
||||
andn %l1, PSR_PIL, %l1 ! oldpsr &= ~PSR_PIL;
|
||||
st %g0, [%l7 + %lo(curproc)] ! curproc = NULL;
|
||||
/*
|
||||
* Save the old process: write back all windows (excluding
|
||||
* the current one). XXX crude; knows nwindows <= 8
|
||||
*/
|
||||
#define SAVE save %sp, -64, %sp
|
||||
wb1: SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; /* 6 of each: */
|
||||
restore; restore; restore; restore; restore; restore
|
||||
|
||||
/* If we've been given a process to switch to, skip the rq stuff */
|
||||
tst %i1
|
||||
bnz,a Lsw_load
|
||||
mov %i1, %l3 ! but move into the expected register first
|
||||
|
||||
#if defined(MULTIPROCESSOR)
|
||||
sethi %hi(IDLE_UP), %g5
|
||||
ld [%g5 + %lo(IDLE_UP)], %g5
|
||||
#else
|
||||
set _C_LABEL(idle_u), %g5
|
||||
#endif
|
||||
mov %l4, %g4 ! save lastproc and %lo(cpcb)
|
||||
mov %l6, %g6 ! before changing windows
|
||||
wr %g0, PSR_S|PSR_PIL, %psr! change to window 0, traps off
|
||||
wr %g0, 2, %wim ! and make window 1 the trap window
|
||||
mov 1, %o0
|
||||
st %g5, [%g6 + %lo(cpcb)] ! cpcb = &idle_u
|
||||
st %o0, [%g5 + PCB_WIM] ! idle_u.pcb_wim = log2(2) = 1
|
||||
#if defined(MULTIPROCESSOR)
|
||||
set USPACE-CCFSZ, %o1 !
|
||||
add %g5, %o1, %sp ! set new %sp
|
||||
#else
|
||||
set _C_LABEL(idle_u) + USPACE-CCFSZ, %sp ! set new %sp
|
||||
#endif
|
||||
mov %g0, %i6 ! paranoid
|
||||
mov %g0, %i7 !
|
||||
|
||||
#ifdef DEBUG
|
||||
mov %g5, %o0 ! %o0 = _idle_u
|
||||
SET_SP_REDZONE(%o0, %o1)
|
||||
#endif
|
||||
! enable traps and continue at splsched()
|
||||
wr %g0, PSR_S|PSR_ET|(IPL_SCHED<<8), %psr
|
||||
|
||||
/* now set up the locals in our new window */
|
||||
mov PSR_S|PSR_ET, %l1 ! oldpsr = PSR_S | PSR_ET;
|
||||
sethi %hi(_C_LABEL(sched_whichqs)), %l2
|
||||
mov %g4, %l4 ! restore lastproc
|
||||
sethi %hi(cpcb), %l6
|
||||
sethi %hi(curproc), %l7
|
||||
|
||||
Lsw_scan:
|
||||
nop; nop; nop ! paranoia
|
||||
ld [%l2 + %lo(_C_LABEL(sched_whichqs))], %o3
|
||||
|
||||
/*
|
||||
* Optimized inline expansion of `which = ffs(whichqs) - 1';
|
||||
* branches to idle if ffs(whichqs) was 0.
|
||||
*/
|
||||
set _C_LABEL(__ffstab), %o2
|
||||
andcc %o3, 0xff, %o1 ! byte 0 zero?
|
||||
bz,a 1f ! yes, try byte 1
|
||||
srl %o3, 8, %o0
|
||||
b 2f ! ffs = ffstab[byte0]; which = ffs - 1;
|
||||
ldsb [%o2 + %o1], %o0
|
||||
1: andcc %o0, 0xff, %o1 ! byte 1 zero?
|
||||
bz,a 1f ! yes, try byte 2
|
||||
srl %o0, 8, %o0
|
||||
ldsb [%o2 + %o1], %o0 ! which = ffstab[byte1] + 7;
|
||||
b 3f
|
||||
add %o0, 7, %o4
|
||||
1: andcc %o0, 0xff, %o1 ! byte 2 zero?
|
||||
bz,a 1f ! yes, try byte 3
|
||||
srl %o0, 8, %o0
|
||||
ldsb [%o2 + %o1], %o0 ! which = ffstab[byte2] + 15;
|
||||
b 3f
|
||||
add %o0, 15, %o4
|
||||
1: ldsb [%o2 + %o0], %o0 ! ffs = ffstab[byte3] + 24
|
||||
addcc %o0, 24, %o0 ! (note that ffstab[0] == -24)
|
||||
bz idle ! if answer was 0, go idle
|
||||
EMPTY
|
||||
2: sub %o0, 1, %o4 ! which = ffs(whichqs) - 1
|
||||
3: /* end optimized inline expansion */
|
||||
|
||||
/*
|
||||
* We found a nonempty run queue. Take its first process.
|
||||
*/
|
||||
set _C_LABEL(sched_qs), %o5 ! q = &qs[which];
|
||||
sll %o4, 3, %o0
|
||||
add %o0, %o5, %o5
|
||||
ld [%o5], %l3 ! p = q->ph_link;
|
||||
cmp %l3, %o5 ! if (p == q)
|
||||
be Lsw_panic_rq ! panic("switch rq");
|
||||
EMPTY
|
||||
ld [%l3], %o0 ! tmp0 = p->p_forw;
|
||||
st %o0, [%o5] ! q->ph_link = tmp0;
|
||||
st %o5, [%o0 + 4] ! tmp0->p_back = q;
|
||||
cmp %o0, %o5 ! if (tmp0 == q)
|
||||
bne Lsw_load
|
||||
EMPTY
|
||||
mov 1, %o1 ! whichqs &= ~(1 << which);
|
||||
sll %o1, %o4, %o1
|
||||
andn %o3, %o1, %o3
|
||||
st %o3, [%l2 + %lo(_C_LABEL(sched_whichqs))]
|
||||
|
||||
Lsw_load:
|
||||
/*
|
||||
* PHASE TWO: NEW REGISTER USAGE:
|
||||
* %l1 = oldpsr (excluding ipl bits)
|
||||
* %l2 =
|
||||
* %l3 = p
|
||||
* %l4 = lastproc
|
||||
* %l5 =
|
||||
* %l6 = %hi(cpcb)
|
||||
* %l7 = %hi(curproc)
|
||||
* %o0 = tmp 1
|
||||
* %o1 = tmp 2
|
||||
* %o2 = tmp 3
|
||||
* %o3 = vm
|
||||
*/
|
||||
|
||||
/* firewalls */
|
||||
ld [%l3 + P_WCHAN], %o0 ! if (p->p_wchan)
|
||||
tst %o0
|
||||
bne Lsw_panic_wchan ! panic("switch wchan");
|
||||
EMPTY
|
||||
ldsb [%l3 + P_STAT], %o0 ! if (p->p_stat != SRUN)
|
||||
cmp %o0, SRUN
|
||||
bne Lsw_panic_srun ! panic("switch SRUN");
|
||||
EMPTY
|
||||
|
||||
/*
|
||||
* Committed to running process p.
|
||||
* It may be the same as the one we were running before.
|
||||
*/
|
||||
mov SONPROC, %o0 ! p->p_stat = SONPROC;
|
||||
stb %o0, [%l3 + P_STAT]
|
||||
|
||||
/* p->p_cpu initialized in fork1() for single-processor */
|
||||
#if defined(MULTIPROCESSOR)
|
||||
sethi %hi(_CISELFP), %o0 ! p->p_cpu = cpuinfo.ci_self;
|
||||
ld [%o0 + %lo(_CISELFP)], %o0
|
||||
st %o0, [%l3 + P_CPU]
|
||||
#endif
|
||||
|
||||
sethi %hi(_C_LABEL(want_resched)), %o0 ! want_resched = 0;
|
||||
#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
|
||||
/* Done with the run queues; release the scheduler lock */
|
||||
call _C_LABEL(sched_unlock_idle)
|
||||
#endif
|
||||
st %g0, [%o0 + %lo(_C_LABEL(want_resched))]! delay slot
|
||||
ld [%l3 + P_ADDR], %g5 ! newpcb = p->p_addr;
|
||||
st %g0, [%l3 + 4] ! p->p_back = NULL;
|
||||
st %l3, [%l7 + %lo(curproc)] ! curproc = p;
|
||||
|
||||
/*
|
||||
* Load the new process. To load, we must change stacks and
|
||||
* and alter cpcb. We must also load the CWP and WIM from the
|
||||
* new process' PCB, since, when we finally return from
|
||||
* the trap, the CWP of the trap window must match the
|
||||
* CWP stored in the trap frame.
|
||||
*
|
||||
* Once the new CWP is set below our local registers become
|
||||
* invalid, so:
|
||||
*
|
||||
* PHASE THREE: NEW REGISTER USAGE:
|
||||
* %g2 = newpsr
|
||||
* %g3 = p
|
||||
* %g4 = lastproc
|
||||
* %g5 = newpcb
|
||||
* %l1 = oldpsr (excluding ipl bits)
|
||||
* %l6 = %hi(cpcb)
|
||||
* %o0 = tmp 1
|
||||
* %o1 = tmp 2
|
||||
* %o2 = tmp 3
|
||||
* %o3 = vm
|
||||
*/
|
||||
|
||||
mov %l3, %g3 ! save p and lastproc to globals
|
||||
mov %l4, %g4 !
|
||||
ld [%g5 + PCB_PSR], %g2 ! newpsr = newpcb->pcb_psr;
|
||||
|
||||
/* traps off while we switch to the new stack */
|
||||
wr %l1, (IPL_SCHED << 8) | PSR_ET, %psr
|
||||
|
||||
/* set new cpcb */
|
||||
st %g5, [%l6 + %lo(cpcb)] ! cpcb = newpcb;
|
||||
|
||||
/* compute new wim */
|
||||
ld [%g5 + PCB_WIM], %o0
|
||||
mov 1, %o1
|
||||
sll %o1, %o0, %o0
|
||||
wr %o0, 0, %wim ! %wim = 1 << newpcb->pcb_wim;
|
||||
/* now must not change %psr for 3 more instrs */
|
||||
/* Clear FP & CP enable bits, as well as the PIL field */
|
||||
/*1,2*/ set PSR_EF|PSR_EC|PSR_PIL, %o0
|
||||
/*3*/ andn %g2, %o0, %g2 ! newpsr &= ~(PSR_EF|PSR_EC|PSR_PIL);
|
||||
/* set new psr, but with traps disabled */
|
||||
wr %g2, (IPL_SCHED << 8)|PSR_ET, %psr ! %psr = newpsr ^ PSR_ET;
|
||||
|
||||
/* load new stack and return address */
|
||||
ldd [%g5 + PCB_SP], %i6 ! <fp,pc> = newpcb->pcb_<sp,pc>
|
||||
add %fp, -CCFSZ, %sp ! set stack frame for this window
|
||||
#ifdef DEBUG
|
||||
mov %g5, %o0
|
||||
SET_SP_REDZONE(%o0, %o1)
|
||||
CHECK_SP_REDZONE(%o0, %o1)
|
||||
#endif
|
||||
|
||||
/* finally, enable traps and continue at splsched() */
|
||||
wr %g2, IPL_SCHED << 8 , %psr ! psr = newpsr;
|
||||
|
||||
/*
|
||||
* Now running p. Make sure it has a context so that it
|
||||
* can talk about user space stuff. (Its pcb_uw is currently
|
||||
* zero so it is safe to have interrupts going here.)
|
||||
*/
|
||||
cmp %g3, %g4 ! p == lastproc?
|
||||
be Lsw_sameproc ! yes, context is still set for p
|
||||
EMPTY
|
||||
|
||||
INCR(_C_LABEL(nswitchdiff)) ! clobbers %o0,%o1
|
||||
ld [%g3 + P_VMSPACE], %o3 ! vm = p->p_vmspace;
|
||||
ld [%o3 + VM_PMAP], %o3 ! pm = vm->vm_map.vm_pmap;
|
||||
ld [%o3 + PMAP_CTX], %o0 ! if (pm->pm_ctx != NULL)
|
||||
tst %o0
|
||||
bnz,a Lsw_havectx ! goto havecontext;
|
||||
ld [%o3 + PMAP_CTXNUM], %i1 ! load context number
|
||||
|
||||
/* p does not have a context: call ctx_alloc to get one */
|
||||
call _C_LABEL(ctx_alloc) ! ctx_alloc(pm);
|
||||
mov %o3, %o0
|
||||
|
||||
ret
|
||||
restore %g0, 1, %o0 ! return (1)
|
||||
|
||||
/* p does have a context: just switch to it */
|
||||
Lsw_havectx:
|
||||
! context is in %i1
|
||||
#if defined(SUN4M) && (defined(SUN4) || defined(SUN4C))
|
||||
NOP_ON_4M_15:
|
||||
b,a 1f
|
||||
b,a 2f
|
||||
#endif
|
||||
1:
|
||||
#if defined(SUN4) || defined(SUN4C)
|
||||
set AC_CONTEXT, %o1
|
||||
stba %i1, [%o1] ASI_CONTROL ! setcontext(vm->vm_pmap.pm_ctxnum);
|
||||
ret
|
||||
restore %g0, 1, %o0 ! return (1)
|
||||
#endif
|
||||
2:
|
||||
#if defined(SUN4M)
|
||||
/*
|
||||
* Flush caches that need to be flushed on context switch.
|
||||
* We know this is currently only necessary on the sun4m hypersparc.
|
||||
*/
|
||||
sethi %hi(CPUINFO_VA + CPUINFO_PURE_VCACHE_FLS), %o0
|
||||
ld [%o0 + %lo(CPUINFO_VA + CPUINFO_PURE_VCACHE_FLS)], %o2
|
||||
jmpl %o2, %o7
|
||||
set SRMMU_CXR, %i2
|
||||
sta %i1, [%i2] ASI_SRMMU ! setcontext(vm->vm_pmap.pm_ctxnum);
|
||||
ret
|
||||
restore %g0, 1, %o0 ! return (1)
|
||||
#endif
|
||||
|
||||
Lsw_sameproc:
|
||||
/*
|
||||
* We are resuming the process that was running at the
|
||||
* call to switch(). Just set psr ipl and return.
|
||||
*/
|
||||
ret
|
||||
restore %g0, %g0, %o0 ! return (0)
|
||||
|
||||
|
||||
/*
|
||||
* Snapshot the current process so that stack frames are up to date.
|
||||
* Only used just before a crash dump.
|
||||
*/
|
||||
ENTRY(snapshot)
|
||||
std %o6, [%o0 + PCB_SP] ! save sp
|
||||
rd %psr, %o1 ! save psr
|
||||
st %o1, [%o0 + PCB_PSR]
|
||||
|
||||
/*
|
||||
* Just like switch(); same XXX comments apply.
|
||||
* 7 of each. Minor tweak: the 7th restore is
|
||||
* done after a ret.
|
||||
*/
|
||||
SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
|
||||
restore; restore; restore; restore; restore; restore; ret; restore
|
||||
|
||||
|
||||
/*
|
||||
* cpu_fork() arrange for proc_trampoline() to run after a process gets
|
||||
* chosen in switch(). The stack frame will contain a function pointer
|
||||
* in %l0, and an argument to pass to it in %l2.
|
||||
*
|
||||
* If the function *(%l0) returns, we arrange for an immediate return
|
||||
* to user mode. This happens in two known cases: after execve(2) of init,
|
||||
* and when returning a child to user mode after a fork(2).
|
||||
*
|
||||
* If were setting up a kernel thread, the function *(%l0) will not return.
|
||||
*/
|
||||
ENTRY(proc_trampoline)
|
||||
/*
|
||||
* Note: cpu_fork() has set up a stack frame for us to run in,
|
||||
* so we can call other functions from here without using
|
||||
* `save ... restore'.
|
||||
*/
|
||||
#ifdef MULTIPROCESSOR
|
||||
/* Finish setup in SMP environment: acquire locks etc. */
|
||||
call _C_LABEL(proc_trampoline_mp)
|
||||
nop
|
||||
#endif
|
||||
|
||||
/* Reset interrupt level */
|
||||
rd %psr, %o0
|
||||
andn %o0, PSR_PIL, %o0 ! psr &= ~PSR_PIL;
|
||||
wr %o0, 0, %psr ! (void) spl0();
|
||||
nop ! psr delay; the next 2 instructions
|
||||
! can safely be made part of the
|
||||
! required 3 instructions psr delay
|
||||
call %l0
|
||||
mov %l1, %o0
|
||||
|
||||
/*
|
||||
* Here we finish up as in syscall, but simplified.
|
||||
* cpu_fork() (or sendsig(), if we took a pending signal
|
||||
* in child_return()) will have set the user-space return
|
||||
* address in tf_pc. In both cases, %npc should be %pc + 4.
|
||||
*/
|
||||
rd %psr, %o0
|
||||
ld [%sp + CCFSZ + 4], %l1 ! pc = tf->tf_pc from cpu_fork()
|
||||
and %o0, PSR_CWP, %o1 ! keep current CWP
|
||||
or %o1, PSR_S, %l0 ! user psr
|
||||
b return_from_syscall
|
||||
add %l1, 4, %l2 ! npc = pc+4
|
||||
|
||||
#else /* ALT_SWITCH_CODE */
|
||||
/*
|
||||
* REGISTER USAGE IN cpu_switch AND switchexit:
|
||||
* This is split into two phases, more or less
|
||||
|
@ -4656,11 +5210,16 @@ idle:
|
|||
SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
|
||||
restore; restore; restore; restore; restore; restore; restore
|
||||
|
||||
mov 1, %g3
|
||||
sethi %hi(IDLE_UP), %g5
|
||||
ld [%g5 + %lo(IDLE_UP)], %g5
|
||||
rd %psr, %g1 ! oldpsr = %psr;
|
||||
andn %g1, PSR_PIL|PSR_PS, %g1! oldpsr &= ~(PSR_PIL|PSR_PS);
|
||||
and %g1, PSR_S|PSR_ET, %g1 ! oldpsr |= PSR_S|PSR_ET;
|
||||
wr %g0, PSR_S|PSR_PS, %psr ! change to window 0, traps off
|
||||
wr %g0, 2, %wim ! and make window 1 the trap window
|
||||
st %g3, [%g5 + PCB_WIM] ! idle_u.pcb_wim = log2(2) = 1
|
||||
!rd %psr, %g1 ! oldpsr = %psr;
|
||||
!andn %g1, PSR_PIL|PSR_PS, %g1! oldpsr &= ~(PSR_PIL|PSR_PS);
|
||||
!and %g1, PSR_S|PSR_ET, %g1 ! oldpsr |= PSR_S|PSR_ET;
|
||||
mov PSR_S|PSR_ET, %g1
|
||||
st %g5, [%g6 + %lo(cpcb)] ! cpcb = &idle_u
|
||||
set USPACE-CCFSZ, %o1
|
||||
add %g5, %o1, %sp ! set new %sp
|
||||
|
@ -5061,6 +5620,7 @@ ENTRY(proc_trampoline)
|
|||
b return_from_syscall
|
||||
add %l1, 4, %l2 ! npc = pc+4
|
||||
|
||||
#endif /* ALT_SWITCH_CODE */
|
||||
/*
|
||||
* {fu,su}{,i}{byte,word}
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue