|
|
Power 6/32 Unix version 1.2b
/* locore.s 4.50 81/05/18 */
# -------------------
#include "../machine/mtpr.h"
#include "../machine/trap.h"
#include "../machine/psl.h"
#include "../machine/pte.h"
#include "../machine/cp.h"
#include "../machine/mem.h"
#include "../h/errno.h"
.set HIGH,0x1f # mask for total disable
.set BERVEC,0x80 # offset into scb of the bus error vector
.set RESTVEC,0x8 # offset into scb of the restart vector
.set MAXPHYSMEM,8*1024*1024-1 # max physical memory
# while we work on CMD/32M !
# look at vmsched.c to see why.
.set MEMUNIT,64*1024 # minimum memory increment
.set NISP,3 # number of interrupt stack pages
.set SYSTEM,0xC0000000 # virtual address of system start
.set PPAGES,0x100000 # Number of possible pages in P0,P1, etc.
/* ACBL for non-negative '_add' */
#define ACBL(_limit,_add,_index,_displ) \
addl2 _add,_index; \
cmpl _index,_limit; \
bleq _displ
/* _ACBL for negative '_add' */
#define _ACBL(_limit,_add,_index,_displ) \
addl2 _add,_index; \
cmpl _index,_limit; \
bgeq _displ
#define MOVC3(_len,_srcaddr,_dstaddr) \
movl _srcaddr,r0; \
movl _dstaddr,r1; \
movl _len,r2; \
movblk
/* Keep address of psl if coming from user mode */
#define CHECK_SFE(_delta) \
bitl $PSL_CURMOD,_delta(sp); \
jeql 1f; \
moval _delta(sp),_user_psl; \
1:
/*
* User structure is UPAGES at top of user space.
*/
.globl _u
.set _u,SYSTEM - UPAGES*NBPG
/*
* Restart stack. Used on power recovery or panic.
* Takes a core-dump and then halts.
*/
.globl _rsstk
_rsstk: .space 1024-8
.globl pwfl_stk
pwfl_stk: .space 4
dumpflag: .space 4
.globl _intstack
_intstack:
.space NISP*NBPG
eintstack:
.data
.globl pwfl_r0
pwfl_r0: .space 14*4 # Enough for r0 - r13
.globl pwfl_sp
pwfl_sp: .long 0x12345678 # r14
.globl pwfl_SCBB
pwfl_SCBB: .long 0x12345678
.globl pwfl_SBR
pwfl_SBR: .long 0x12345678
.globl pwfl_SLR
pwfl_SLR: .long 0x12345678
.globl pwfl_P0BR
pwfl_P0BR: .long 0x12345678
.globl pwfl_P0LR
pwfl_P0LR: .long 0x12345678
.globl pwfl_P1BR
pwfl_P1BR: .long 0x12345678
.globl pwfl_P1LR
pwfl_P1LR: .long 0x12345678
.globl pwfl_P2BR
pwfl_P2BR: .long 0x12345678
.globl pwfl_P2LR
pwfl_P2LR: .long 0x12345678
.globl pwfl_IPL
pwfl_IPL: .long 0x12345678
.globl pwfl_DCK
pwfl_DCK: .long 0x12345678
.globl pwfl_CCK
pwfl_CCK: .long 0x12345678
.globl pwfl_PCBB
pwfl_PCBB: .long 0x12345678
.globl pwfl_ISP
pwfl_ISP: .long 0x12345678
.globl pwfl_KSP
pwfl_KSP: .long 0x12345678
.globl pwfl_USP
pwfl_USP: .long 0x12345678
.globl pwfl_MME
pwfl_MME: .long 0x12345678
.globl pwfl_PSL
pwfl_PSL: .long 0x12345678
/*
* Do a dump.
* Called by auto-restart.
* May be called manually.
*/
.align 2
.text
.globl _Xdoadump
.globl _doadump
_Xdoadump: # CP brings Tahoe here on power recovery
loadr $0x3fff,pwfl_r0 # Restore r0 - r13
movl pwfl_sp,sp # Restore sp ( = r14 )
mtpr pwfl_SCBB,$SCBB
mtpr pwfl_SBR,$SBR # Restore all re_loadable registers
mtpr pwfl_SLR,$SLR
mtpr pwfl_P0BR,$P0BR
mtpr pwfl_P0LR,$P0LR
mtpr pwfl_P1BR,$P1BR
mtpr pwfl_P1LR,$P1LR
mtpr pwfl_P2BR,$P2BR
mtpr pwfl_P2LR,$P2LR
mtpr pwfl_IPL,$IPL
mtpr pwfl_DCK,$DCK
mtpr pwfl_CCK,$CCK
mtpr pwfl_PCBB,$PCBB
mtpr pwfl_ISP,$ISP
mtpr pwfl_KSP,$KSP
mtpr pwfl_USP,$USP
/* now go to mapped mode */
/* Have to change PC to system addresses */
mtpr $1,$PACC # Thoroughly clean up caches.
mtpr $1,$PADC
mtpr $1,$TBIA
mtpr pwfl_MME,$MME
# Restore PSW. Last thing to be done.
bicpsw $0xff
bispsw pwfl_PSL+2 # Set original bits back (just in case..)
jmp *$0f
_doadump:
.word 0
#define _rsstkmap _Sysmap+12
# Tahoe storage, scb, rsstk, interrupt stack
0:
mtpr $HIGH,$IPL
andl2 $0!PG_PROT,_rsstkmap
orl2 $PG_KW,_rsstkmap # Make dump stack r/w
tstl dumpflag # dump only once!
bneq 1f
movl $1,dumpflag
mtpr $0,$TBIA
movab dumpflag,sp
callf $4,_dumpsys
1:
halt
/*
* Interrupt vector routines
*/
.globl _waittime
#define SCBVEC(name) \
.align 2; \
.globl _X/**/name; \
_X/**/name
#define PANIC(msg) clrl _waittime; pushab 1f; \
callf $8,_panic; 1: .asciz msg
#define PRINTF(n,msg) pushab 1f; callf $(n+2)*4,_printf; MSG(msg)
#define MSG(msg) .data; 1: .asciz msg; .text
# these registers are not restored by the C-compiler.
#define PUSHR pushl r0; pushl r1;
#define POPR movl (sp)+, r1; movl (sp)+, r0;
# mask for error code on stack.
SCBVEC(buserr):
CHECK_SFE(12)
PUSHR
andl3 12(sp),$ERRCD,r0
jeql go_on
cmpl r0,$APE
jneq 1f
halt # Address parity error !!!
1: cmpl r0,$VBE
jneq go_on
halt # Versabus error !!!
go_on:
pushab 2*4(sp) # Pointer to parameters
callf $8,_buserror
POPR
movab 8(sp),sp # Remove hardware parameters
rei
SCBVEC(powfail): # We should be on interrupt stack now.
movpsl pwfl_PSL # Keeps all flags, etc.
storer $0x3fff,pwfl_r0 # Saves r0 - r13
moval 0(sp),pwfl_sp # Saves sp ( = r14 )
mfpr $SBR,pwfl_SBR # Save all re_loadable registers
mfpr $SLR,pwfl_SLR
mfpr $P0BR,pwfl_P0BR
mfpr $P0LR,pwfl_P0LR
mfpr $P1BR,pwfl_P1BR
mfpr $P1LR,pwfl_P1LR
mfpr $P2BR,pwfl_P2BR
mfpr $P2LR,pwfl_P2LR
mfpr $IPL,pwfl_IPL
mfpr $MME,pwfl_MME
mfpr $DCK,pwfl_DCK
mfpr $CCK,pwfl_CCK
mfpr $PCBB,pwfl_PCBB
mfpr $ISP,pwfl_ISP
mfpr $SCBB,pwfl_SCBB
mfpr $KSP,pwfl_KSP
mfpr $USP,pwfl_USP
moval _Xdoadump-SYSTEM,_scb+RESTVEC
halt
SCBVEC(stray):
PUSHR; PRINTF(0, "******* Undefined interrupt *******\n"); POPR;
rei
SCBVEC(soft15):
SCBVEC(soft14):
SCBVEC(soft13):
SCBVEC(soft12):
SCBVEC(soft11):
SCBVEC(soft10):
#ifndef SIMIO
SCBVEC(soft9):
#endif
SCBVEC(soft7):
SCBVEC(soft6):
SCBVEC(soft5):
SCBVEC(soft4):
#ifndef SIMIO
SCBVEC(soft3):
SCBVEC(soft2):
SCBVEC(soft1):
#endif
PUSHR
PRINTF(0, "******* Undefined software interrupt *******\n")
POPR;
rei
#ifdef SIMIO
SCBVEC(soft2):
#endif
SCBVEC(cnrint):
CHECK_SFE(4)
PUSHR; pushl $CPCONS; callf $8,_cnrint; POPR; incl _cnt+V_INTR; rei
#ifdef SIMIO
SCBVEC(soft3):
#endif
SCBVEC(cnxint):
CHECK_SFE(4)
PUSHR; pushl $CPCONS; callf $8,_cnxint; POPR; incl _cnt+V_INTR; rei
SCBVEC(rmtrint):
CHECK_SFE(4)
PUSHR; pushl $CPREMOT; callf $8,_cnrint; POPR; incl _cnt+V_INTR; rei
SCBVEC(rmtxint):
CHECK_SFE(4)
PUSHR; pushl $CPREMOT; callf $8,_cnxint; POPR; incl _cnt+V_INTR; rei
#ifdef SIMIO
SCBVEC(soft9):
#endif
SCBVEC(hardclock):
CHECK_SFE(4)
PUSHR
pushl 4+2*4(sp); pushl 4+2*4(sp);
callf $12,_hardclock # hardclock(pc,psl)
POPR;
incl _cnt+V_INTR ## temp so not to break vmstat -= HZ
rei
SCBVEC(softclock):
CHECK_SFE(4)
PUSHR
pushl 4+2*4(sp); pushl 4+2*4(sp);
callf $12,_softclock # softclock(pc,psl)
POPR;
rei
/*
* Trap and fault vector routines
*/
#define TRAP(a) pushl $T_/**/a; jbr alltraps
/*
* Ast delivery (profiling and/or reschedule)
*/
/*
* When we want to reschedule we will force a memory fault by setting the m.s.b
* of P0LR. Then , on memory fault if m.s.b of P0LR is on we will clear it and
* TRAP(astflt).
*
*/
# if this bit is on it is an ast.
#define ASTBIT 0x00100000
#define P0MASK 0xc0000000
SCBVEC(kspnotval):
CHECK_SFE(4)
pushl $0; TRAP(KSPNOTVAL)
SCBVEC(privinflt):
CHECK_SFE(4)
pushl $0; TRAP(PRIVINFLT)
SCBVEC(resopflt):
CHECK_SFE(4)
pushl $0; TRAP(RESOPFLT)
SCBVEC(resadflt):
CHECK_SFE(4)
pushl $0; TRAP(RESADFLT)
SCBVEC(bptflt):
CHECK_SFE(4)
pushl $0; TRAP(BPTFLT)
SCBVEC(tracep):
CHECK_SFE(4)
pushl $0; TRAP(TRCTRAP)
SCBVEC(alignflt):
CHECK_SFE(4)
pushl $0; TRAP(ALIGNFLT)
SCBVEC(arithtrap):
CHECK_SFE(8)
TRAP(ARITHTRAP)
SCBVEC(protflt):
CHECK_SFE(12)
bitl $1,(sp)+
jneq segflt
TRAP(PROTFLT)
segflt:
TRAP(SEGFLT)
SCBVEC(fpm): # Floating Point eMulation
.globl _fpemulate
CHECK_SFE(24)
callf $24,_fpemulate # We want psl, pc and opcode
# not to be removed by the ret.
# Don't modify registers now !!
tstl (sp) # Stack= PSL, PC, return_code
jneq _Xarithtrap # If not OK, emulate F.P. exception
movab 4(sp),sp # Else remove return_code and
rei
SCBVEC(sfexcep):
CHECK_SFE(4)
pushl $0
TRAP(ASTFLT)
SCBVEC(transflt):
CHECK_SFE(12)
bitl $1,(sp)+
bneq tableflt
pageflt:
TRAP(PAGEFLT)
tableflt:
TRAP(TABLEFLT)
alltraps:
mfpr $USP,-(sp); callf $4,_trap; mtpr (sp)+,$USP
incl _cnt+V_TRAP
movab 8(sp),sp # pop type, code
mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
rei
SCBVEC(syscall):
CHECK_SFE(8)
pushl $T_SYSCALL
mfpr $USP,-(sp); callf $4,_syscall; mtpr (sp)+,$USP
incl _cnt+V_SYSCALL
movab 8(sp),sp # pop type, code
mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
rei
/*
* System page table
*/
#define vaddr(x) ((((x)-_Sysmap)/4)*NBPG+SYSTEM)
#define SYSMAP(mname, vname, npte) \
_/**/mname: .globl _/**/mname; \
.space npte*4; \
.globl _/**/vname; \
.set _/**/vname,vaddr(_/**/mname)
.data
.align 2
SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE )
SYSMAP(VMEMbeg ,vmembeg ,0 )
SYSMAP(VMEMmap ,vmem ,IOSIZE )
SYSMAP(VMEMend ,vmemend ,0 )
SYSMAP(Usrptmap ,usrpt ,USRPTSIZE )
SYSMAP(Forkmap ,forkutl ,UPAGES )
SYSMAP(Xswapmap ,xswaputl ,UPAGES )
SYSMAP(Xswap2map,xswap2utl ,UPAGES )
SYSMAP(Swapmap ,swaputl ,UPAGES )
SYSMAP(Pushmap ,pushutl ,UPAGES )
SYSMAP(Vfmap ,vfutl ,UPAGES )
/*
SYSMAP(IOmap ,ioutl ,(MAXBPTE+1) )
*/
SYSMAP(VDmap ,vdutl ,(MAXBPTE+1) )
SYSMAP(CYmap ,cyutl ,(TBUFSIZ+1) )
SYSMAP(CMAP1 ,CADDR1 ,1 )
SYSMAP(CMAP2 ,CADDR2 ,1 )
SYSMAP(mmap ,vmmap ,1 )
SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT )
SYSMAP(camap ,cabase ,16*CLSIZE )
SYSMAP(ecamap ,calimit ,0 )
SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*CLSIZE)
eSysmap:
.globl _Syssize
.set _Syssize,(eSysmap-_Sysmap)/4
.text
/*
* Initialization
*
* IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
*
*/
.align 2
.globl start
start:
.word 0
/* set system control block base and system page table params */
mtpr $_scb-SYSTEM,$SCBB
mtpr $_Sysmap-SYSTEM,$SBR
mtpr $_Syssize,$SLR
/* double map the kernel into the virtual user addresses of phys mem */
/* (to be on the safe side.This is supposed to run in system sace. ) */
mtpr $_Sysmap,$P0BR
mtpr $_Syssize,$P0LR
mtpr $_Sysmap,$P1BR # Against Murphy
mtpr $_Syssize,$P1LR
/* set ISP */
movl $_intstack-SYSTEM+NISP*NBPG,sp # Still physical !
mtpr $_intstack+NISP*NBPG,$ISP
/* count up memory */
clrl r7
1: pushl $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
addl2 $MEMUNIT,r7
cmpl r7,$MAXPHYSMEM
bleq 1b
9:
/* clear memory from kernel bss and pages for proc 0 u. and page table */
movab _edata,r6
movab _end,r5
andl2 $0!SYSTEM,r6
andl2 $0!SYSTEM,r5
addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5
1: clrl (r6); ACBL( r5,$4,r6,1b)
/* trap() and syscall() save r0-r13 in the entry mask (per ../h/reg.h) */
/* For floating point emulation, we do same for 'fpemulate' */
orw2 $0x01fff,_trap
orw2 $0x01fff,_syscall
orw2 $0x01fff,_fpemulate
/* initialize system page table: scb and int stack writeable */
clrl r2
movab eintstack,r1
andl2 $0!SYSTEM,r1
shrl $PGSHIFT,r1,r1 # r1-page number of eintstack.
/* Start by making the processor storage read/only */
orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
/* Other parts of the system are read/write for kernel */
1: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write + phys=virtual
aoblss r1,r2,1b
/* make rsstk read-only as red zone for interrupt stack */
andl2 $0!PG_PROT,_rsstkmap
orl2 $PG_V|PG_KR,_rsstkmap # Make dump stack r/w
/* make kernel text space read-only */
/*
* HAVE TO CHECK ALL THE MAGIC CONSTANTS USED HERE : $xxxxxx */
movab _etext+NBPG-1,r1
andl2 $0!SYSTEM,r1
shrl $PGSHIFT,r1,r1
1: orl3 $PG_V|PG_KR,r2,_Sysmap[r2]
aoblss r1,r2,1b
/* make kernel data, bss, read-write */
movab _end+NBPG-1,r1
andl2 $0!SYSTEM,r1
shrl $PGSHIFT,r1,r1
1: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]
aoblss r1,r2,1b
/* now go to mapped mode */
/* Have to change both PC and SP to system addresses */
mtpr $1,$TBIA
mtpr $1,$PADC /* needed by HW parity & ECC logic */
mtpr $1,$PACC /* just in case */
mtpr $1,$MME
movab SYSTEM(sp),sp
.globl go_virt
go_virt:
jmp *$0f
0:
/* disable any interrupts */
movl $0,_intenable
/* init mem sizes */
shrl $PGSHIFT,r7,_maxmem
movl _maxmem,_physmem
movl _maxmem,_freemem
/* setup context for proc[0] == Scheduler */
movab _end-SYSTEM+NBPG-1,r6
andl2 $0!(NBPG-1),r6 # make page boundary
/* setup page table for proc[0] */
shrl $PGSHIFT,r6,r3 # r3 = btoc(r6)
orl3 $PG_V|PG_KW,r3,_Usrptmap # init first upt entry
incl r3 # r3 - next page
movab _usrpt,r0 # r0 - first user page
mtpr r0,$TBIS
/* init p0br, p0lr */
mtpr r0,$P0BR # No P0 for proc[0]
mtpr $0,$P0LR
mtpr r0,$P1BR # No P1 either
mtpr $0,$P1LR
/* init p2br, p2lr */
movab NBPG(r0),r0
movl $PPAGES-UPAGES,r1
mtpr r1,$P2LR
moval -4*PPAGES(r0),r2
mtpr r2,$P2BR
/* setup mapping for UPAGES of _u */
clrl r2;
movl $SYSTEM,r1
addl2 $UPAGES,r3
jbr 2f
1: decl r3
moval -NBPG(r1),r1; # r1 = virtual add of next (downward) _u page
subl2 $4,r0 # r0 = pte address
orl3 $PG_V|PG_URKW,r3,(r0)
mtpr r1,$TBIS
2: aobleq $UPAGES,r2,1b
/* initialize (slightly) the pcb */
movab UPAGES*NBPG(r1),PCB_KSP(r1) # KSP starts at end of _u
movl r1,PCB_USP(r1) # USP starts just below _u
mfpr $P0BR,PCB_P0BR(r1)
mfpr $P0LR,PCB_P0LR(r1)
mfpr $P1BR,PCB_P1BR(r1)
mfpr $P1LR,PCB_P1LR(r1)
mfpr $P2BR,PCB_P2BR(r1)
mfpr $P2LR,PCB_P2LR(r1)
movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt
movl r11,PCB_R11(r1) # r11 obtained from CP on boot
movab 1f,PCB_PC(r1) # initial pc
clrl PCB_PSL(r1) # kernel mode, ipl=0
movw $0xff,PCB_CKEY(r1) # give him a code key
movw $0xff,PCB_DKEY(r1) # give him a data key
shll $PGSHIFT,r3,r3
mtpr r3,$PCBB # first pcbb (physical ! )
/* Go to a 'normal' process mode (kernel) */
ldpctx
rei # Actually 'returns' to the next instruction:
/* put signal trampoline code in u. area */
1: movab _u,r0
movl sigcode+0,PCB_SIGC+0(r0)
movl sigcode+4,PCB_SIGC+4(r0)
movl sigcode+8,PCB_SIGC+8(r0)
movl sigcode+12,PCB_SIGC+12(r0)
/* save reboot flags in global _boothowto */
movl r11,_boothowto
/* calculate firstaddr, and call main() */
movab _end-SYSTEM+NBPG-1,r0
shrl $PGSHIFT,r0,-(sp)
addl2 $UPAGES+1,(sp) # First physical unused page number
callf $8,_main
/* proc[1] == /etc/init now running here in kernel mode; run icode */
pushl $PSL_CURMOD # User mode PSL
pushl $0 # PC = 0 (virtual now)
rei
/* signal trampoline code: it is known that this code takes up to 16 */
/* bytes in pcb.h and in the code above */
/* The following user stack layout was set up by machdep.c/sendsig */
/* routine: */
/* */
/* +---------------+ */
/* | Last PSL |\ */
/* +---------------+ > for rei */
/* :-->| Last PC |/ */
/* | +---------------+ */
/* :___|__* SP |\ */
/* +---------------+ | */
/* | sigmask | | */
/* +---------------+ > cleaned by kcall $139 (sigcleanup) */
/* :-->| u.u_onstack | | */
/* | +---------------+ | */
/* :___|_* copy of SCP |/ */
/* | +---------------+ */
/* | | Process' r0 | */
/* | +---------------+ */
/* | | Process' r1 | */
/* | +---------------+ */
/* | | Handler addr. |\ */
/* | +---------------+ | */
/* :___|_* SCP | | */
/* +---------------+ > cleaned by ret from calls */
/* | u.u_code | | */
/* +---------------+ | */
/* | signal number|/ */
/* +---------------+ */
/* */
/* * Stack when entering sigcode; setup by sendsig(); */
/* */
.align 2
sigcode: # When the process executes this code
# (located in its u. structure), it
# is in user mode !
calls $4*4+4,*12(sp) # 4 words popped from stack when this call returns
movl (sp)+,r1
movl (sp)+,r0
kcall $139 # Signal cleanup
rei # From user mode to user mode !
/*
* Primitives
*/
/*
* badaddr(addr, len)
* see if access addr with a len type instruction causes a machine check
* len is length of access (1=byte, 2=short, 4=long)
* r0 = 0 means good(exists); r0 =1 means does not exist.
*/
.globl _badaddr
_badaddr:
.word 0x1c # Keep r4,r3,r2
mfpr $IPL,r1
mtpr $HIGH,$IPL
movl _scb+BERVEC,r2
movl 4(fp),r3
movl 8(fp),r4
movab 9f,_scb+BERVEC
bbc $0,r4,1f; tstb (r3)
1: bbc $1,r4,1f; tstw (r3)
1: bbc $2,r4,1f; tstl (r3)
1: clrl r0 # made it w/o machine checks
2: movl r2,_scb+BERVEC
mtpr r1,$IPL
ret
.align 2
9: # Here we catch buss error (if it comes)
andl3 4(sp),$ERRCD,r0
cmpl r0,$APE
jneq 1f
halt # Address parity error !!!
1: cmpl r0,$VBE
jneq 1f
halt # Versabus error
1:
movl $1,r0 # Anything else = bad address
movab 8(sp),sp # discard buss error trash
movab 2b,(sp) # new program counter on stack.
rei
/*
* badcyaddr(addr)
* see if access tape master controller addr causes a bus error
* r0 = 0: no error; r0 = 1: timeout error.
*/
.globl _badcyaddr
_badcyaddr:
.word 0x0c # Keep r3,r2
mfpr $IPL,r1
mtpr $HIGH,$IPL
movl _scb+BERVEC,r2
clrl r3
movab 9f,_scb+BERVEC
movob $-1, *4(fp)
1: aobleq $1000, r3, 1b
clrl r0 # made it w/o machine checks
2: movl r2,_scb+BERVEC
mtpr r1,$IPL
ret
.align 2
9: # Here we catch buss error (if it comes)
andl3 4(sp),$ERRCD,r0
cmpl r0,$APE
jneq 1f
halt # Address parity error !!!
1: cmpl r0,$VBE
jneq 1f
halt # Versabus error
1:
movl $1,r0 # Anything else = timeout
movab 8(sp),sp # discard buss error trash
movab 2b,(sp) # new program counter on stack.
rei
_bcopy: .globl _bcopy
.word 0x4 # save r2
# Called by ovbcopy(from,dst,len)
movl 4(fp),r0
movl 8(fp),r1
movl 12(fp),r2
movblk
ret
_ovbcopy: .globl _ovbcopy
.word 0x001c
movl 4(fp),r0
movl 8(fp),r1
movl 12(fp),r2
cmpl r0,r1
bgtru 1f # normal forward case
beql 2f # equal, nothing to do
addl2 r2,r0 # may be overlapping
cmpl r0,r1
bgtru 3f
subl2 r2,r0 # normal forward case
1:
movblk
2:
ret
3:
addl2 r2,r1 # overlapping, must do backwards
subl3 r0,r1,r3
movl r2,r4
jbr 5f
4:
subl2 r3,r0
subl2 r3,r1
movl r3,r2
movblk
subl2 r3,r0
subl2 r3,r1
subl2 r3,r4
5:
cmpl r4,r3
jgtr 4b
movl r4,r2
subl2 r2,r0
subl2 r2,r1
movblk
ret
/*
* bzero (base, count)
* zero out a block starting at 'base', size 'count'.
*/
_bzero:
.globl _bzero
.word 0x4
movl $1f,r0 # r0 = null source string
movl 4(fp),r1 # r1 = destination address
movl 8(fp),r2 # r2 = count
movs3
ret
1:
.byte 0
_copyin: .globl _copyin # the _Copyin subroutine in VAX
# became _copyin procedure for TAHOE
.word 0x0004
movl 12(fp),r0 # copy length
blss ersb
movl 4(fp),r1 # copy user address
cmpl $NBPG,r0 # probing one page or less ?
bgeq cishort # yes
ciloop:
prober $1,(r1),$NBPG # bytes accessible ?
beql ersb # no
addl2 $NBPG,r1 # incr user address ptr
_ACBL ($NBPG+1,$-NBPG,r0,ciloop) # reduce count and loop
cishort:
prober $1,(r1),r0 # bytes accessible ?
beql ersb # no
MOVC3 (12(fp),4(fp),8(fp))
clrl r0
ret
ersb:
movl $EFAULT,r0
ret
_copyout: .globl _copyout # the _Copyout subroutine in VAX
# became _copyout procedure for TAHOE
.word 0x04
movl 12(fp),r0 # get count
blss ersb
movl 8(fp),r1 # get user address
cmpl $NBPG,r0 # can do in one probew?
bgeq coshort # yes
coloop:
probew $1,(r1),$NBPG # bytes accessible?
beql ersb # no
addl2 $NBPG,r1 # increment user address
_ACBL ($NBPG+1,$-NBPG,r0,coloop) # reduce count and loop
coshort:
probew $1,(r1),r0 # bytes accessible?
beql ersb # no
MOVC3 (12(fp),4(fp),8(fp))
clrl r0
ret
/*
* non-local goto's
*/
.globl _setjmp # the _Setjmp subroutine in VAX
# became _setjmp procedure for TAHOE
_setjmp:
.word 0x0
movl 4(fp),r2
storer $0x1ff8,(r2)
addl2 $40,r2
movl (fp),(r2)
addl2 $4,r2
movab 8(fp),(r2)
addl2 $4,r2
movl -8(fp),(r2)
clrl r0
ret
.globl _longjmp # the _Longjmp subroutine in VAX
# became _longjmp procedure for TAHOE
_longjmp:
.word 0x0000
movl 4(fp),r2
_Longjmp: # called from swtch
loadr $0x3ff8,(r2)
addl2 $44,r2
movl (r2),r1
addl2 $4,r2
movab (sp),r0
cmpl r1,r0 # must be a pop
bgequ lj2
pushab lj1
callf $8,_panic
lj2:
movl r1,sp
jmp *(r2)
lj1: .asciz "longjmp"
.globl _whichqs
.globl _qs
.globl _cnt
.globl _noproc
.comm _noproc,4
.globl _runrun
.comm _runrun,4
/*
* The following primitives use the fancy TAHOE instructions.
* _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 fancy TAHOE instructions.
*
* Call should be made at spl8(), and p->p_stat should be SRUN
*/
.globl _setrq
_setrq:
.word 0x4
movl 4(fp),r0
tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0
beql set1 ##
pushab set3 ##
callf $8,_panic ##
set1:
movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4
shar $2,r1,r1
shal $1,r1,r2
moval _qs[r2],r2
insque (r0),*4(r2) # at end of queue
shal r1,$1,r1
orl2 r1,_whichqs # mark queue non-empty
ret
set3: .asciz "setrq"
/*
* remrq(p), using fancy TAHOE instructions
*
* Call should be made at spl8().
*/
.globl _remrq
_remrq:
.word 0x0
movl 4(fp),r0
movzbl P_PRI(r0),r1
shar $2,r1,r1
bbs r1,_whichqs,rem1
pushab rem3 # it wasn't recorded to be on its q
callf $8,_panic
rem1:
remque (r0)
bneq rem2 # q not empty yet
shal r1,$1,r1
mcoml r1,r1
andl2 r1,_whichqs # mark queue empty
rem2:
clrl P_RLINK(r0) ## for firewall checking
ret
rem3: .asciz "remrq"
.globl __insque
__insque:
.word 0
insque *4(fp), *8(fp)
ret
.globl __remque
__remque:
.word 0
remque *4(fp)
ret
/*
* Masterpaddr is the p->p_addr of the running process on the master
* processor. When a multiprocessor system, the slave processors will have
* an array of slavepaddr's.
*/
.globl _masterpaddr
.data
_masterpaddr:
.long 0
.text
sw0: .asciz "swtch"
/*
* swtch(), using fancy TAHOE instructions
*/
.globl _swtch
_swtch:
.word 0x0
movl (fp),fp # prepare for rei
movl (sp),4(sp) # saved pc
tstl (sp)+
movpsl 4(sp)
movl $1,_noproc
clrl _runrun
mtpr0: mtpr $0,$IPL # must allow interrupts here
sw1: ffs _whichqs,r0 # look for non-empty queue
bgeq sw1a
brb sw1 # this is an idle loop!
sw1a: mtpr $0x18,$IPL # lock out all so _whichqs==_qs
bbc r0,_whichqs,mtpr0 # proc moved via lbolt interrupt
shal $1,r0,r1
moval _qs[r1],r1
movl (r1),r2 # r2 = p = highest pri process
remque *(r1)
bvc sw2 # make sure something was there
sw1b: pushab sw0
callf $8,_panic
sw2: bneq sw3
shal r0,$1,r1
mcoml r1,r1
andl2 r1,_whichqs # no more procs in this queue
sw3:
clrl _noproc
tstl P_WCHAN(r2) ## firewalls
bneq sw1b ##
movzbl P_STAT(r2),r3 ##
cmpl $SRUN,r3 ##
bneq sw1b ##
clrl P_RLINK(r2) ##
movl *P_ADDR(r2),r0
movl r0,_masterpaddr
shal $PGSHIFT,r0,r0 # r0 = pcbb(p)
/* mfpr $PCBB,r1 # resume of current proc is easy
* cmpl r0,r1
*/ beql res0
incl _cnt+V_SWTCH
brb swresume
/* fall into... */
/*
* global cache key used if cant use proc index as key
* (e.g. NPROC>=255)
* otherwise used for temporary storage of key
*/
.data
_globkey:
.long 0
.text
/*
* resume(pf)
*/
.globl _resume
_resume:
.word 0x0
shal $PGSHIFT,4(fp),r0 # r0 = pcbb(p)
movl (fp),fp # prepare for rei
movl (sp)+,4(sp) # saved pc
tstl (sp)+
movpsl 4(sp)
swresume:
mtpr $0x18,$IPL # no interrupts, please
movl _CMAP2,_u+PCB_CMAP2 # yech
svpctx
mtpr r0,$PCBB
ldpctx
movl _u+PCB_CMAP2,_CMAP2 # yech
mtpr $_CADDR2,$TBIS
res0:
tstl _u+PCB_SSWAP
beql res1
movl _u+PCB_SSWAP,r2
clrl _u+PCB_SSWAP
movab _Longjmp,(sp)
clrl 4(sp) # PSL = kernel mode, IPL=0
res1:
#ifdef GLOBKEY
aoblss $256,_globkey,res2 # define new cache key
mtpr $0,$PACC # out of keys, purge all
mtpr $0,$PADC
movl $1,_globkey
res2:
mtpr _globkey,$CCK
#else
res3:
movzwl _u+PCB_CKEY,_globkey
mtpr _globkey,$CCK
res4:
movzwl _u+PCB_DKEY,_globkey
#endif
mtpr _globkey,$DCK
rei
/*
* {fu,su},{byte,word}
*/
.globl _fuiword
.globl _fuword
_fuiword:
_fuword:
.word 0x0
prober $1,*4(fp),$4
beql fserr
movl *4(fp),r0
ret
fserr:
mnegl $1,r0
ret
.globl _fuibyte
.globl _fubyte
_fuibyte:
_fubyte:
.word 0x0
prober $1,*4(fp),$1
beql fserr
movzbl *4(fp),r0
ret
.globl _suiword
.globl _suword
_suiword:
_suword:
.word 0x0
probew $1,*4(fp),$4
beql fserr
movl 8(fp),*4(fp)
clrl r0
ret
.globl _suibyte
.globl _subyte
_suibyte:
_subyte:
.word 0x0
probew $1,*4(fp),$1
beql fserr
movb 11(fp),*4(fp)
clrl r0
ret
/*
* Copy 1 relocation unit (NBPG bytes)
* from user virtual address to physical address
*/
_copyseg: .globl _copyseg
.word 0x0
orl3 $PG_V|PG_KW,8(fp),_CMAP2
mtpr $_CADDR2,$TBIS # invalidate entry for copy
MOVC3 ($NBPG,4(fp),$_CADDR2)
ret
/*
* clearseg(physical_page_number);
*
* zero out physical memory
* specified in relocation units (NBPG bytes)
* This routine was optimized for speed on Tahoe.
*/
_clearseg: .globl _clearseg
.word 0
orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1
mtpr $_CADDR1,$TBIS
movl $255,r0 # r0 = limit
clrl r1 # r1 = index of cleared long
1:
clrl _CADDR1[r1]
aobleq r0,r1,1b
ret
/*
* if ( useracc(address, count, mode) ) ....
* Check address.
* Given virtual address, byte count, and rw flag
* returns 0 on no access.
* Note : it is assumed that on all calls to this routine,
* mode=0 means write access, mode=1 means read access.
*/
_useracc: .globl _useracc
.word 0x4
movl $1,r2 # r2 = 'user mode' for probew/probew
probes:
movl 4(fp),r0 # get va
movl 8(fp),r1 # count
tstl 12(fp) # test for read access ?
bneq userar # yes
cmpl $NBPG,r1 # can we do it in one probe ?
bgeq uaw2 # yes
uaw1:
probew r2,(r0),$NBPG
beql uaerr # no access
addl2 $NBPG,r0
_ACBL($NBPG+1,$-NBPG,r1,uaw1)
uaw2:
probew r2,(r0),r1
beql uaerr
movl $1,r0
ret
userar:
cmpl $NBPG,r1
bgeq uar2
uar1:
prober r2,(r0),$NBPG
beql uaerr
addl2 $NBPG,r0
_ACBL($NBPG+1,$-NBPG,r1,uar1)
uar2:
prober r2,(r0),r1
beql uaerr
movl $1,r0
ret
uaerr:
clrl r0
ret
/*
* if ( kernacc(address, count, mode) ) ....
* Check address.
* Given virtual address, byte count, and rw flag
* returns 0 on no access.
* Same as useracc routine but checks for kernel access rights.
*/
_kernacc: .globl _kernacc
.word 0x4
clrl r2 # r2 = 0 means kernel mode probe.
jbr probes # Dijkstra would get gastric distress here.
/*
* addupc - increment some histogram counter
* in the profiling buffer
*
* addupc(pc, prof, counts)
* long pc , counts; Only least significant word of 'counts' is added.
* struct uprof *prof;
*
* struct uprof { # profile arguments
* short *r_base; # buffer base
* unsigned pr_size; # buffer size
* unsigned pr_off; # pc offset
* unsigned pr_scale; # pc scaling
* }
*/
.globl _addupc
_addupc:
.word 4
movl 8(fp),r2 # r2 points to structure
subl3 8(r2),4(fp),r0 # r0 = PC - lowpc
jlss 9f # PC < lowpc , out of range !
shrl $1,r0,r0 # the unit is words
shrl $1,12(r2),r1 # ditto for scale
emul r1,r0,$0,r0
shrq $14,r0,r0
tstl r0 # too big
jneq 9f
cmpl r1,4(r2) # Check buffer overflow
jgequ 9f
probew $1,*0(r2)[r1],$2 # counter accessible?
jeql 9f
shrl $1,r1,r1 # make r1 word index
addw2 14(fp),*0(r2)[r1]
9: ret
SCBVEC(udintr0):
SCBVEC(xpintr0):
jbr _Xstray
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.