.data .asciz "@(#)vax.s 1.1 86/02/03 Copyr 1986 Sun Micro" .even .text /* * Copyright (c) 1986 by Sun Microsystems, Inc. */ /* * Emulate VAX instructions on the 68020. */ #include "../h/param.h" #include "../machine/asm_linkage.h" #include "../machine/mmu.h" #include "../machine/psl.h" #include "assym.s" /* * 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(splie) RAISE(3) ENTRY(splclock) RAISE(5) ENTRY(splzs) SETPRI(6) ENTRY(spl7) SETPRI(7) ENTRY2(spl6,spl5) SETPRI(5) ENTRY(spl4) SETPRI(4) ENTRY(spl3) SETPRI(3) ENTRY(spl2) SETPRI(2) ENTRY(spl1) SETPRI(1) ENTRY(spl0) SETPRI(0) ENTRY(splx) movw sr,d0 movw sp@(6),sr 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 /* * _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 btst #SPROCIO_BIT-24,a0@(P_FLAG) | if he's getting PROCIO'd, jne 3f | we leave him alone 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 3: 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 btst #SPROCIO_BIT-24,a0@(P_FLAG) | if he's getting PROCIO'd, jne rem2a | we leave him alone 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) rem2a: rts 1: pea 3f jsr _panic 3: .asciz "remrq" .even /* * swtch(), using semi-fancy 68020 instructions */ ENTRY(swtch) movw sr,sp@- | save processor priority movl #1,_noproc clrl _runrun bclr #AST_SCHED_BIT-24,_u+PCB_P0LR 2: bfffo _whichqs{#0:#32},d0 | test if any bit on cmpl #32,d0 jne 3f | found one 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 movl a0,sp@- jsr _resume addqw #4,sp 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. */ .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) * * Assumes that there is only one real page to worry about (UPAGES = 1), * that the kernel stack starts below the u area in the middle of * a page, that the redzone is below that and is always marked * for no access across all contexts, the default sfc and dfs are * set to FC_MAP, and that we are running on the u area kernel stack * when we are called. */ SAVREGS = 0xFCFC ENTRY(resume) tstw _fppstate | is fpp present and enabled? jle 1f | branch if not fsave _u+U_FP_ISTATE | save internal state tstw _u+U_FP_ISTATE | test for null state jeq 1f | branch if so fmovem fpc/fps/fpi,_u+U_FPS_CTRL | save control registers fmovem fp0-fp7,_u+U_FPS_REGS | save fp data registers movl _masterprocp,_fpprocp | remember whose regs are still loaded 1: movl sp@,_u+PCB_REGS | save return pc in pcb movl sp@(4),a0 | a0 contains proc pointer movw sr,_u+PCB_SR+2 | save the current psw in u area orw #SR_INTPRI,sr | mask interrupts moveml #SAVREGS,_u+PCB_REGS+4 | save data/address regs movl a0,_masterprocp | set proc pointer for new process lea eintstack,sp | use the interrupt stack moveq #KCONTEXT,d0 movsb d0,CONTEXTBASE | invalidate context lea U_MAPVAL,a1 | a1 has address used to access pme for u area movl a0@(P_ADDR),a2 | get p_addr (address of pte's), a2 is scratch movl a2@,d0 | get u pte movsl d0,a1@ | and set pme /* * Check to see if we already have context. If so and * SPTECHG bit is not on then set up the next context. */ tstl a0@(P_CTX) | check p->p_ctx jeq 1f | if zero, skip ahead btst #SPTECHG_BIT-24,a0@(P_FLAG) | check (p->p_flag & SPTECHG) jne 1f | if SPTECHG bit is on, skip ahead movl a0@(P_CTX),a1 movw a1@(CTX_CONTEXT),d0 | get context number in d0 movsb d0,CONTEXTBASE | set up the context 1: tstw _fppstate | is fpp present and enabled? jle 1f | branch if not tstw _u+U_FP_ISTATE | test for null state jeq 0f | branch if so cmpl _fpprocp,a0 | check if we were last proc using fpp beq 0f | if so, jump and skip loading ext regs fmovem _u+U_FPS_REGS:w,fp0-fp7 | restore fp data registers fmovem _u+U_FPS_CTRL,fpc/fps/fpi | restore control registers 0: frestore _u+U_FP_ISTATE | restore internal state 1: moveml _u+PCB_REGS+4,#SAVREGS | restore data/address regs | Note: we just changed stacks movw _u+PCB_SR+2,sr tstl _u+PCB_SSWAP jeq 1f movl _u+PCB_SSWAP,sp@(4) | blech... clrl _u+PCB_SSWAP movw #SR_LOW,sr jmp _longjmp 1: rts