Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

477 lines
11 KiB
ArmAsm

.data
.asciz "@(#)vax.s 1.1 92/07/30 SMI"
.even
.text
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*
* Forked from version 1.42
*/
/*
* Emulate VAX instructions on the 68020.
*/
#include <sys/param.h>
#include <machine/asm_linkage.h>
#include <machine/enable.h>
#include <machine/mmu.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include "fpa.h"
#include "assym.s"
.globl _uunix
/*
* Macro to raise prio level,
* avoid dropping prio if already at high level.
* NOTE - Assumes that we are never in "master" mode.
*/
#define RAISE(level) \
movw sr,d0; \
andw #(SR_SMODE+SR_INTPRI),d0; \
cmpw #(SR_SMODE+(/**/level*0x100)),d0; \
jge 0f; \
movw #(SR_SMODE+(/**/level*0x100)),sr; \
0: rts
#define SETPRI(level) \
movw sr,d0; \
movw #(SR_SMODE+(/**/level*0x100)),sr; \
rts
ENTRY(splimp)
RAISE(3)
ENTRY(splnet)
RAISE(1)
ENTRY(splclock)
RAISE(5)
ENTRY(splzs)
SETPRI(6)
ENTRY(spl7)
SETPRI(7)
ALTENTRY(spltty)
ALTENTRY(splbio)
ALTENTRY(splhigh)
ENTRY2(spl6,spl5)
SETPRI(5)
ENTRY(spl4)
SETPRI(4)
ENTRY(spl3)
SETPRI(3)
ENTRY(spl2)
SETPRI(2)
ENTRY2(spl1,splsoftclock)
SETPRI(1)
ENTRY(spl0)
SETPRI(0)
ENTRY(splx)
movw sr,d0
movw sp@(6),sr
rts
/*
* splr is like splx but will only raise the priority and never drop it
*/
ENTRY(splr)
movw sr,d0
andw #(SR_SMODE+SR_INTPRI),d0
movw sp@(6),d1
andw #(SR_SMODE+SR_INTPRI),d1
cmpw d1,d0
jge 0f
movw d1,sr
0:
rts
/*
* splvm will raise the processor priority to the value implied by splvm_val
* which is initialized by the autoconfiguration code to pritospl(SPLMB).
*/
.globl _splvm_val
ENTRY(splvm)
movw sr,d0
andw #(SR_SMODE+SR_INTPRI),d0
movw _splvm_val,d1
cmpw d1,d0
jge 0f
movw d1,sr
0:
rts
ENTRY(_insque)
movl sp@(4),a0
movl sp@(8),a1
movl a1@,a0@
movl a1,a0@(4)
movl a0,a1@
movl a0@,a1
movl a0,a1@(4)
rts
ENTRY(_remque)
movl sp@(4),a0
movl a0@,a1
movl a0@(4),a0
movl a1,a0@
movl a0,a1@(4)
rts
ENTRY(scanc)
movl sp@(8),a0 | string
movl sp@(12),a1 | table
movl sp@(16),d1 | mask
movl d2,sp@-
clrw d2
movl sp@(8),d0 | len
subqw #1,d0 | subtract one for dbxx
jmi 1f
2:
movb a0@+,d2 | get the byte from the string
movb a1@(0,d2:w),d2 | get the corresponding table entry
andb d1,d2 | apply the mask
dbne d0,2b | check for loop termination
1:
addqw #1,d0 | dbxx off by one
movl sp@+,d2
rts
ENTRY(movtuc)
movl a2,sp@-
movl sp@(12),a0 | from
movl sp@(16),a1 | to
movl sp@(20),a2 | table
clrw d1
movl sp@(8),d0 | len
subqw #1,d0 | subtract one for dbxx
jmi 1f
2:
movb a0@+,d1 | get the byte from the first string
movb a2@(0,d1:w),d1 | get the corresponding table entry
movb d1,a1@+ | store it
dbeq d0,2b | check for loop termination
bne 1f | terminated because the count ran out
subql #1,a1 | moved one too many bytes
1:
movl a1,d0 | final pointer minus original pointer
subl sp@(16),d0 | is number of characters moved
movl sp@+,a2
rts
/*
* _whichqs tells which of the 32 queues _qs have processes in them
* setrq puts processes into queues, remrq removes them from queues
* The running process is on no queue, other processes are on a
* queue related to p->p_pri, divided by 4 actually to shrink the
* 0-127 range of priorities into the 32 available queues.
*/
/*
* setrq(p), using semi-fancy 68020 instructions.
*
* Call should be made at spl6(), and p->p_stat should be SRUN
*/
ENTRY(setrq)
movl sp@(4),a0 | get proc pointer
tstl a0@(P_RLINK) | firewall: p->p_rlink must be 0
jne 1f
moveq #31,d1
clrl d0
movb a0@(P_PRI),d0 | get the priority
lsrl #2,d0 | divide by 4
subl d0,d1
lea _qs,a1
movl a1@(4,d1:l:8),a1| qs[d1].ph_rlink, 8 == sizeof (qs[0])
movl a1@,a0@ | insque(p, blah)
movl a1,a0@(4)
movl a0,a1@
movl a0@,a1
movl a0,a1@(4)
bfset _whichqs{d0:#1} | set appropriate bit in whichqs
rts
1:
pea 2f
jsr _panic
2: .asciz "setrq"
.even
/*
* remrq(p), using semi-fancy 68020 instructions
*
* Call should be made at spl6().
*/
ENTRY(remrq)
movl sp@(4),a0
clrl d0
movb a0@(P_PRI),d0
lsrl #2,d0 | divide by 4
bftst _whichqs{d0:#1}
jeq 1f
movl a0@,a1 | remque(p);
movl a0@(4),a0
movl a1,a0@
movl a0,a1@(4)
cmpl a0,a1
jne 2f | queue not empty
bfclr _whichqs{d0:#1} | queue empty, clear the bit
2:
movl sp@(4),a0
clrl a0@(P_RLINK)
rts
1:
pea 3f
jsr _panic
3: .asciz "remrq"
.even
/*
* swtch(), using semi-fancy 68020 instructions
* Only for heavyweight processes.
*/
.globl _qrunflag, _runqueues
ENTRY(swtch)
movw sr,sp@- | save processor priority
movl #1,_noproc
clrl _runrun
movl _uunix, a0
bclr #AST_SCHED_BIT-24, a0@(PCB_FLAGS)
2:
bfffo _whichqs{#0:#32},d0 | test if any bit on
cmpl #32,d0
jne 3f | found one
tstb _qrunflag | need to run stream queues?
beq 1f | no
movw #SR_LOW,sr | run queues at priority 0
jsr _runqueues | go do it
jra 2b | scan run queue immediately
1:
#ifdef LWP
.globl ___Nrunnable, _lwpschedule
tstl ___Nrunnable | any runnable threads?
jeq 0f | no
movw #SR_LOW,sr | run queues at priority 0
jsr _lwpschedule
movl _masterprocp, sp@-
jsr _setmmucntxt
addqw #4,sp
jra 2b
0:
#endif LWP
stop #SR_LOW | must allow interrupts here
.globl idle
idle: | wait here for interrupts
jra 2b | try again
3:
movw #SR_HIGH,sr | lock out all so _whichqs == _qs
moveq #31,d1
subl d0,d1
bfclr _whichqs{d0:#1}
jeq 2b | proc moved via lbolt interrupt
lea _qs,a0
movl a0@(0,d1:l:8),a0| get qs[d1].ph_link = p = highest pri process
movl a0,d1 | save it
movl a0@,a1 | remque(p);
cmpl a0,a1 | is queue empty?
jne 4f
8:
pea 9f
jsr _panic
9:
.asciz "swtch"
.even
4:
movl a0@(4),a0
movl a1,a0@
movl a0,a1@(4)
cmpl a0,a1
jeq 5f | queue empty
bfset _whichqs{d0:#1} | queue not empty, set appropriate bit
5:
movl d1,a0 | restore p
clrl _noproc
tstl a0@(P_WCHAN) || firewalls
jne 8b ||
cmpb #SRUN,a0@(P_STAT) ||
jne 8b ||
clrl a0@(P_RLINK) ||
addql #1,_cnt+V_SWTCH
cmpl _masterprocp,a0 | restore of current proc is easy
jeq 6f
movl a0,sp@-
jsr _resume
addqw #4,sp
6:
movw sp@+,sr | restore processor priority
rts
/*
* fpprocp is the pointer to the proc structure whose external
* state (i.e. registers) was last loaded into the 68881.
* XXX - temporarily this optimization is not used until
* we have per process enabling and disabling of '81 since
* an frestore of null state resets the external '81 state.
*/
.data
.globl _fpprocp
_fpprocp: .long 0 | struct proc *fpprocp;
.text
/*
* masterprocp is the pointer to the proc structure for the currently
* mapped u area. It is used to set up the mapping for the u area
* by the debugger since the u area is not in the Sysmap.
*/
.data
.globl _masterprocp
_masterprocp: .long 0 | struct proc *masterprocp;
.text
/*
* resume(p)
*
* Saves all the needed register state into the "old" user area given
* by uunix and then restores all the register state from the user
* area given by process p and sets uunix to point to that u area.
* Resume will also try to set up the address space for the process.
*/
#define SAVREGS d2-d7/a2-a7
ENTRY(resume)
movl _uunix, a0
tstw _fppstate | is fpp present and enabled?
jle 1f | branch if not
fsave a0@(U_FP_ISTATE) | save internal state
tstb a0@(U_FP_ISTATE) | null state? (vers == FPIS_VERSNULL)
jeq 1f | branch if so
fmovem fpc/fps/fpi,a0@(U_FPS_CTRL) | save control registers
fmovem fp0-fp7,a0@(U_FPS_REGS) | save fp data registers
| XXX - fpprocp not used until we get rid of frestores with null state
| movl _masterprocp,_fpprocp | remember whose regs are still loaded
1:
movl sp@,a0@(PCB_REGS) | save return pc in pcb
movw sr,a0@(PCB_SR+2) | save the current psw in u area
moveml SAVREGS,a0@(PCB_REGS+4) | save data/address regs
tstl _masterprocp | have a current process?
jeq 1f | skip if not
movl _masterprocp,a2 | does it
movl a2@(P_AS),d0 | have an address space?
jeq 1f | skip if not
movl d0,sp@- | find out memory claim for
jsr _rm_asrss | as associated with this process
addqw #4,sp | clean up stack
movl _uunix, a0 | restore a0
movl d0,a2@(P_RSSIZE) | store with process
1:
#if NFPA > 0
/*
* fpa_save() is inlined here to moveml 12 regs in two instructions.
* We use a2 to contain the fpa address so that it is preserved across
* the call to fpa_shutdown and we pick out SAVEFPA regs so that a2
* is not used and we have a total of 12 regs.
*/
#define SAVEFPA d0-d7/a3-a6
#define FPA_MAXLOOP 512
tstw a0@(U_FPA_FLAGS) | test if this process uses FPA
jeq 1f | FPA is not used skip saving FPA regs
| Begin of assembly fpa_save
movl #FPA_MAXLOOP-1,d1 | loop at most FPA_MAXLOOP times
movl _fpa,a2 | get fpa adddress
0:
movl a2@(FPA_PIPE_STATUS),d0 | get status
andl #FPA_STABLE,d0 | test for stability
bne 2f | != 0 means pipe is stable
dbra d1,0b | busy, try again
jsr _fpa_shutdown | timed out, shut it down
jra 3f | skip reg save
2:
moveml a2@(FPA_STATE),SAVEFPA | load 12 FPA regs
moveml SAVEFPA,a0@(U_FPA_STATUS) | save to u.u_fpa_status
3:
andb #~ENA_FPA,_enablereg | turn off FPA enable bit so FPA is
movb _enablereg,d0 | protected from unexpected accesses
movsb d0,ENABLEREG
1:
#endif NFPA > 0
movl sp@(4),a2 | a2 contains proc pointer
orw #SR_INTPRI,sr | ok, now mask interrupts
| since must hve atomic set of
| masterprocp and uunix
movl a2,_masterprocp | set proc pointer for new process
lea eintstack,sp | use the interrupt stack
movl a2@(P_UAREA), _uunix | switch u areas
/*
* Check to see if we already have context. If so, then set up
* to use the context otherwise to default to the kernel context.
*/
movl a2@(P_AS),d0 | get p->p_as
jeq 0f | skip ahead if NULL (kernel process)
movl d0,a0
movl a0@(A_HAT_CTX),d0 | get as->a_hat.hat_ctx
jeq 0f | skip ahead if NULL (no ctx allocated)
movl d0,a0
movw _ctx_time,a0@(C_TIME)
addqw #1,_ctx_time | ctx->c_time = ctx_time++;
movb a0@(C_NUM),d0 | get ctx->c_num
bra 1f
0:
moveq #KCONTEXT,d0 | no context - use kernel context
1:
movsb d0,CONTEXT_REG | switch context
movl _uunix, a0
tstw _fppstate | is fpp present and enabled?
jle 1f | branch past fpp and fpa code if not
tstb a0@(U_FP_ISTATE) | null state? (vers == FPIS_VERSNULL)
jeq 0f | branch if so
| XXX - fpprocp not used until we get rid of frestores with null state
| cmpl _fpprocp,a2 | check if we were last proc using fpp
| beq 0f | if so, jump and skip loading ext regs
fmovem a0@(U_FPS_REGS),fp0-fp7 | restore fp data registers
fmovem a0@(U_FPS_CTRL),fpc/fps/fpi | restore control registers
0:
frestore a0@(U_FP_ISTATE) | restore internal state
#if NFPA > 0
tstw a0@(U_FPA_FLAGS) | test if this process uses FPA
jeq 1f | no, skip restoring FPA context
movl _uunix, sp@-
jsr _fpa_restore | yes, restore FPA context
addqw #4, sp
movl _uunix, a0
#endif NFPA > 0
1:
/*
* a0 points to current u area. u area and kernel stack
* should already be set before resume() was called.
*/
moveml a0@(PCB_REGS+4),SAVREGS | restore data/address regs
/*
* Note: we just changed stacks from the interrupt stack
* we were temporarily using to the new process stack!
*/
movw a0@(PCB_SR+2),sr
rts