|
|
BSD 4.3tahoe
#ifdef LOCORE
#define U_PROCP 144
#define U_EOSYS 273
#define P_LINK 0
#define P_RLINK 4
#define P_XLINK 108
#define P_ADDR 16
#define P_PRI 21
#define P_STAT 23
#define P_WCHAN 96
#define P_TSIZE 68
#define P_SSIZE 76
#define P_P0BR 104
#define P_SZPT 66
#define P_TEXTP 100
#define P_FLAG 44
#define P_DKEY 164
#define P_CKEY 160
#define SSLEEP 1
#define SRUN 3
#define V_SWTCH 0
#define V_TRAP 4
#define V_SYSCALL 8
#define V_INTR 12
#define V_SOFT 16
#define V_FPE 116
#define V_ALIGN 120
#define MCLBYTES 1024
#define NBPG 1024
#define PGSHIFT 10
#define UPAGES 6
#define CLSIZE 1
#define MAXPHYS 65536
#define SYSPTSIZE 9216
#define USRPTSIZE 1024
#define VBIOSIZE 1020
#define MSGBUFPTECNT 4
#define NMBCLUSTERS 256
#define PCB_KSP 0
#define PCB_USP 4
#define PCB_R0 8
#define PCB_R1 12
#define PCB_R2 16
#define PCB_R3 20
#define PCB_R4 24
#define PCB_R5 28
#define PCB_R6 32
#define PCB_R7 36
#define PCB_R8 40
#define PCB_R9 44
#define PCB_R10 48
#define PCB_R11 52
#define PCB_R12 56
#define PCB_R13 60
#define PCB_FP 60
#define PCB_PC 64
#define PCB_PSL 68
#define PCB_P0BR 72
#define PCB_P0LR 76
#define PCB_P1BR 80
#define PCB_P1LR 84
#define PCB_P2BR 88
#define PCB_P2LR 92
#define PCB_ACH 96
#define PCB_ACL 100
#define PCB_HFS 104
#define PCB_SAVACC 108
#define PCB_SZPT 112
#define PCB_CMAP2 116
#define PCB_SSWAP 120
#define PCB_SIGC 124
#define SCB_DOADUMP 8
#define SCB_BUSERR 128
#define SCB_DEVBASE 64
#endif
/*
* @(#)scb.s 7.1 (Berkeley) 5/21/88
*/
/*
* System control block
*/
#define STRAY .long _Xstray
#define STRAY8 STRAY;STRAY;STRAY;STRAY;STRAY;STRAY;STRAY;STRAY
#define KS(a) .long _X/**/a
#define IS(a) .long _X/**/a
_scb: .globl _scb
/* 000 */ STRAY; IS(powfail); IS(doadump); STRAY;
/* 004 */ STRAY; STRAY; STRAY; IS(hardclock);
/* 008 */ STRAY; STRAY; IS(cnrint); IS(cnxint);
/* 00c */ IS(rmtrint); IS(rmtxint); STRAY; STRAY;
/* 010 */ IS(kdbintr); STRAY; STRAY; IS(netintr);
/* 014 */ STRAY; STRAY; STRAY; IS(softclock);
/* 018 */ STRAY; STRAY; STRAY; STRAY;
/* 01c */ STRAY; STRAY; STRAY; STRAY;
/* 020 */ IS(buserr); STRAY; STRAY; STRAY;
/* 024 */ STRAY; STRAY; STRAY; STRAY;
/* 028 */ STRAY; STRAY; STRAY; KS(syscall);
/* 02c */ KS(privinflt); KS(resopflt); KS(resadflt); KS(protflt);
/* 030 */ KS(transflt); IS(kspnotval); KS(tracep); KS(bptflt);
/* 034 */ KS(arithtrap); KS(alignflt); KS(sfexcep); KS(fpm);
/* 038 */ STRAY; STRAY; STRAY; STRAY;
/* 03c */ STRAY; STRAY; STRAY; STRAY;
/* device interrupt vectors */
/* 040 */ STRAY8; STRAY8; STRAY8; STRAY8;
/* 060 */ STRAY8; STRAY8; STRAY8; STRAY8;
/* 080 */ STRAY8; STRAY8; STRAY8; STRAY8;
/* 0a0 */ STRAY8; STRAY8; STRAY8; STRAY8;
/* 0c0 */ STRAY8; STRAY8; STRAY8; STRAY8;
/* 0e0 */ STRAY8; STRAY8; STRAY8; STRAY8;
#define I_CLOCK 0
#define I_CNR 4
#define I_CNX 8
#define I_RMTR 12
#define I_RMTX 16
#define I_BUSERR 20
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)locore.s 7.6 (Berkeley) 5/1/89
* 9/8/89 (bostic) -- added delay in wbadaddr from 7.10
* This had already been patched, but I have no idea by whom; the
* following lines had been added:
*
* #if NVX > 0
* ADDMAP( NVX * 16384/NBPG )
* #endif
*/
#include "../tahoe/mtpr.h"
#include "../tahoe/trap.h"
#include "../tahoe/psl.h"
#include "../tahoe/pte.h"
#include "../tahoe/cp.h"
#include "../tahoe/mem.h"
#include "../tahoe/SYS.h"
#include "../tahoemath/fp.h"
#include "errno.h"
#include "syscall.h"
#include "cmap.h"
.set HIGH,0x1f # mask for total disable
.set NISP,3 # number of interrupt stack pages
.set SYSTEM,0xC0000000 # virtual address of system start
.set PPAGES,0x100000 # 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(_srcaddr,_dstaddr,_len) \
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
.globl pwfl_stk
_rsstk:
.space 1024-8
pwfl_stk:
.space 4
dumpflag:
.space 4
.globl _intstack
_intstack:
.space NISP*NBPG
eintstack:
/*
* Power failure storage block and
* macros for saving and restoring.
*/
#define POWERFAIL(id,longs) \
.globl pwfl_/**/id \
pwfl_/**/id: .space longs*4
.data
POWERFAIL(r0, 14) # r0-r13
POWERFAIL(sp, 1) # r14
POWERFAIL(SCBB, 1) # system control block base
POWERFAIL(SBR, 1) # system pte base
POWERFAIL(SLR, 1) # system pte length
POWERFAIL(P0BR, 1) # p0 pte base
POWERFAIL(P0LR, 1) # p0 pte length
POWERFAIL(P1BR, 1) # p1 pte base
POWERFAIL(P1LR, 1) # p1 pte length
POWERFAIL(P2BR, 1) # p2 pte base
POWERFAIL(P2LR, 1) # p2 pte length
POWERFAIL(IPL, 1) # interrupt priority level
POWERFAIL(DCK, 1) # data cache key
POWERFAIL(CCK, 1) # code cache key
POWERFAIL(PCBB, 1) # process control block base
POWERFAIL(ISP, 1) # interrupt stack pointer
POWERFAIL(KSP, 1) # kernel mode stack pointer
POWERFAIL(USP, 1) # user mode stack pointer
POWERFAIL(MME, 1) # memory management enable
POWERFAIL(PSL, 1) # processor status longword
/*
* Save current state in power fail storage block.
*/
#define SAVEpwfl() \
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
/*
* Restore state saved in power fail block and
* jmp to location specified after (possibly)
* enabling memory management.
*/
#define RESTOREpwfl(loc) \
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 \
\
bicpsw $0xff # Restore PSW. \
bispsw pwfl_PSL+2 # Set original bits back (just in case..) \
# 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 MME. Last thing to be done. \
jmp loc
/*
* Do a dump.
* Called by auto-restart.
* May be called manually.
*/
.align 2
.text
.globl _Xdoadump
.globl _doadump
_Xdoadump: # CP comes here after power fail
RESTOREpwfl(*0f) # restore state
_doadump:
.word 0
0: mtpr $HIGH,$IPL
#define _rsstkmap _Sysmap+12 # powerfail storage, scb, rsstk, int stack
tstl dumpflag # dump only once!
bneq 1f
andl2 $~PG_PROT,_rsstkmap
orl2 $PG_KW,_rsstkmap # Make dump stack r/w
mtpr $0,$TBIA
movl $1,dumpflag
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
/*
* r0-r5 are saved across all faults and interrupts.
* Routines below and those hidden in vbglue.s (device
* interrupts) invoke the PUSHR/POPR macros to execute
* this. Also, certain stack frame offset calculations
* use this, using the REGSPC definition (and FPSPC defined below).
*/
#define REGSPC 6*4
#define PUSHR movab -REGSPC(sp),sp; storer $0x3f,(sp)
#define POPR loadr $0x3f,(sp); movab REGSPC(sp),sp
/*
* Floating point state is saved across faults and
* interrupts. The state occupies 4 longwords on
* the stack:
* precision indicator (single = 0/double = 1)
* double representation of accumulator
* save accumulator status flag (pcb_savacc)
*/
#define FPSPC (4*4)
#define SAVE_FPSTAT(_delta) \
bitl $PSL_DBL,_delta(sp); \
beql 1f; \
pushl $1; \
pushd; \
jmp 2f; \
1: pushl $0; \
pushl $0; \
stf -(sp); \
2: tstl _u+PCB_SAVACC; \
bneq 3f; \
moval 0(sp),_u+PCB_SAVACC; \
orl2 $2,8(sp);\
3: pushl $0;
#define REST_FPSTAT \
tstl (sp)+; \
bitl $2,8(sp);\
beql 1f;\
movl $0,_u+PCB_SAVACC; \
1: bitl $1,8(sp); \
beql 2f; \
ldd (sp); \
jmp 3f; \
2: ldf (sp); \
3: moval 12(sp),sp;
#define REST_ACC \
tstl _u+PCB_SAVACC; \
beql 2f; \
movl _u+PCB_SAVACC,r1; \
andl3 $(EXPMASK|SIGNBIT),(r1),-(sp); \
cmpl $0x80000000,(sp)+; \
bneq 3f; \
clrl (r1); \
3: bitl $1,8(r1); \
beql 1f; \
ldd (r1); \
jmp 2f; \
1: ldf (r1); \
2: ;
.data
nofault: .space 4 # bus error non-local goto label
.text
SCBVEC(buserr):
CHECK_SFE(12)
SAVE_FPSTAT(12)
incl _intrcnt+I_BUSERR # keep stats...
pushl r0 # must save
andl3 24(sp),$ERRCD,r0 # grab pushed MER value
cmpl r0,$APE # address parity error?
jneq 1f
halt
1: cmpl r0,$VBE # versabus error?
jneq 2f
halt
2:
movl (sp)+,r0 # restore r0 and...
bitl $PSL_CURMOD,4*4+3*4(sp) # check if happened in user mode?
jeql 3f # yes, then shift stack up for trap...
movl 12(sp),16(sp) # sorry, no space for which-buss...
movl 8(sp),12(sp)
movl 4(sp),8(sp)
movl 0(sp),4(sp)
movl $T_BUSERR,0(sp) # push trap type code and...
jbr alltraps # ...merge with all other traps
3: # kernel mode, check to see if...
tstl nofault # ...doing peek/poke?
jeql 4f # nofault set? if so, jump to it...
movl nofault,4*4+2*4(sp) # ...setup for non-local goto
clrl nofault
jbr 5f
4:
PUSHR
pushab 4*4+REGSPC(sp) # address of bus error parameters
callf $8,_buserror
POPR
5:
REST_FPSTAT
movab 8(sp),sp # remove bus error parameters
rei
SCBVEC(powfail): # We should be on interrupt stack now.
SAVEpwfl() # save machine state
moval _Xdoadump-SYSTEM,_scb+SCB_DOADUMP
halt
SCBVEC(stray):
incl _cnt+V_INTR # add to statistics
rei
#include "../net/netisr.h"
.globl _netisr
SCBVEC(netintr):
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR
#include "imp.h"
#if NIMP > 0
bbc $NETISR_IMP,_netisr,1f;
andl2 $~(1<<NETISR_IMP),_netisr
callf $4,_impintr;
1:
#endif
#ifdef INET
bbc $NETISR_IP,_netisr,1f
andl2 $~(1<<NETISR_IP),_netisr
callf $4,_ipintr
1:
#endif
#ifdef NS
bbc $NETISR_NS,_netisr,1f
andl2 $~(1<<NETISR_NS),_netisr
callf $4,_nsintr
1:
#endif
bbc $NETISR_RAW,_netisr,1f
andl2 $~(1<<NETISR_RAW),_netisr
callf $4,_rawintr
1:
incl _cnt+V_SOFT
POPR; REST_FPSTAT
rei
SCBVEC(cnrint):
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR;
pushl $CPCONS; callf $8,_cnrint;
incl _intrcnt+I_CNR
incl _cnt+V_INTR
POPR; REST_FPSTAT;
rei
SCBVEC(cnxint):
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR;
pushl $CPCONS; callf $8,_cnxint;
incl _intrcnt+I_CNX
incl _cnt+V_INTR
POPR; REST_FPSTAT;
rei
SCBVEC(rmtrint):
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR;
pushl $CPREMOT; callf $8,_cnrint;
incl _intrcnt+I_RMTR
incl _cnt+V_INTR
POPR; REST_FPSTAT;
rei
SCBVEC(rmtxint):
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR;
pushl $CPREMOT; callf $8,_cnxint;
incl _intrcnt+I_RMTX
incl _cnt+V_INTR
POPR; REST_FPSTAT;
rei
#define PUSHPCPSL pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp);
SCBVEC(hardclock):
tstl _clk_enable
bneq 1f
rei
1:
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR
PUSHPCPSL # push pc and psl
callf $12,_hardclock # hardclock(pc,psl)
incl _intrcnt+I_CLOCK
incl _cnt+V_INTR ## temp so not to break vmstat -= HZ
POPR; REST_FPSTAT
rei
SCBVEC(softclock):
CHECK_SFE(4)
SAVE_FPSTAT(4); PUSHR;
PUSHPCPSL # push pc and psl
callf $12,_softclock # softclock(pc,psl)
incl _cnt+V_SOFT
POPR; REST_FPSTAT
rei
/*
* Stray VERSAbus interrupt catch routines
*/
.data
#define PJ .align 2; callf $4,_Xvstray
.globl _catcher
_catcher:
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
.align 2
.globl _cold
_cold: .long 0x3
.text
SCBVEC(vstray):
.word 0
bbc $0,_cold,2f # system running?
bbc $1,_cold,1f # doing autoconfig?
jbr 3f # random interrupt, ignore
1:
mfpr $IPL,r12 # ...setup br and cvec
subl3 $_catcher+7,-8(fp),r11; shar $3,r11,r11
addl2 $SCB_DEVBASE,r11
jbr 3f
2:
PUSHR
subl3 $_catcher+7,-8(fp),r0; shar $3,r0,r0
addl3 $SCB_DEVBASE,r0,-(sp);
mfpr $IPL,-(sp)
PRINTF(2, "stray intr ipl %x vec %x\n")
POPR
3: moval 0f,-8(fp); ret # pop callf frame...
0: rei # ...and return
/*
* Trap and fault vector routines
*/
#define TRAP(a) pushl $T_/**/a; jbr alltraps
/*
* Ast delivery (profiling and/or reschedule)
*/
SCBVEC(kspnotval):
CHECK_SFE(4)
pushl $0;
SAVE_FPSTAT(8)
TRAP(KSPNOTVAL)
SCBVEC(privinflt):
CHECK_SFE(4)
pushl $0;
SAVE_FPSTAT(8)
TRAP(PRIVINFLT)
SCBVEC(resopflt):
CHECK_SFE(4)
pushl $0;
SAVE_FPSTAT(8)
TRAP(RESOPFLT)
SCBVEC(resadflt):
CHECK_SFE(4)
pushl $0;
SAVE_FPSTAT(8)
TRAP(RESADFLT)
SCBVEC(bptflt):
CHECK_SFE(4)
pushl $0;
SAVE_FPSTAT(8)
TRAP(BPTFLT)
SCBVEC(kdbintr):
CHECK_SFE(4);
pushl $0;
SAVE_FPSTAT(8);
TRAP(KDBTRAP);
SCBVEC(tracep):
CHECK_SFE(4)
pushl $0;
SAVE_FPSTAT(8)
TRAP(TRCTRAP)
SCBVEC(alignflt):
#ifdef ALIGN
bitl $PSL_CURMOD,4(sp)
jeql align_excp # Can't emulate for kernel mode !
jbr non_aligned # Only emulated for user mode.
align_excp:
#else
CHECK_SFE(4)
#endif
pushl $0;
SAVE_FPSTAT(8)
TRAP(ALIGNFLT)
SCBVEC(arithtrap):
CHECK_SFE(8)
SAVE_FPSTAT(8)
TRAP(ARITHTRAP)
SCBVEC(protflt):
CHECK_SFE(12)
bitl $1,(sp)+
jneq segflt
SAVE_FPSTAT(8)
TRAP(PROTFLT)
segflt:
SAVE_FPSTAT(8)
TRAP(SEGFLT)
SCBVEC(fpm): # Floating Point Emulation
#ifdef FPE
CHECK_SFE(16)
SAVE_FPSTAT(16)
incl _cnt+V_FPE # count emulation traps
callf $4,_fpemulate
REST_FPSTAT
#endif
moval 8(sp),sp # Pop operand
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
SAVE_FPSTAT(8)
TRAP(ASTFLT)
SCBVEC(transflt):
CHECK_SFE(12)
bitl $2,(sp)+
bneq tableflt
pageflt:
SAVE_FPSTAT(8)
TRAP(PAGEFLT)
tableflt:
SAVE_FPSTAT(8)
TRAP(TABLEFLT)
#define REST_STACK movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
alltraps:
mfpr $USP,-(sp);
callf $4,_trap;
mtpr (sp)+,$USP
incl _cnt+V_TRAP
REST_STACK # pop type, code, and fp stuff
mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
rei
SCBVEC(syscall):
CHECK_SFE(8)
SAVE_FPSTAT(8)
pushl $T_SYSCALL
mfpr $USP,-(sp);
callf $4,_syscall;
mtpr (sp)+,$USP
incl _cnt+V_SYSCALL
REST_STACK # pop type, code, and fp stuff
mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
rei
/*
* System page table.
*
* Mbmap and Usrptmap are enlarged by CLSIZE entries
* as they are managed by resource maps starting with index 1 or CLSIZE.
*/
#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)
#define ADDMAP(npte) .space (npte)*4
.data
.align 2
SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE )
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(CMAP1 ,CADDR1 ,1 )
SYSMAP(CMAP2 ,CADDR2 ,1 )
SYSMAP(mmap ,vmmap ,1 )
SYSMAP(alignmap ,alignutl ,1 ) /* XXX */
SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT )
SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE )
SYSMAP(kmempt ,kmembase ,300*CLSIZE )
#ifdef GPROF
SYSMAP(profmap ,profbase ,600*CLSIZE )
#endif
/*
* Enlarge kmempt as needed for bounce buffers allocated
* by tahoe controllers.
*/
#include "hd.h"
#if NHD > 0
ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) )
#endif
#include "dk.h"
#if NDK > 0
ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) )
#endif
#include "yc.h"
#if NYC > 0
ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) )
#endif
#include "mp.h"
ADDMAP( NMP*14 )
SYSMAP(ekmempt ,kmemlimit ,0 )
SYSMAP(VMEMbeg ,vmembeg ,0 )
SYSMAP(VMEMmap ,vmem ,VBIOSIZE )
SYSMAP(VMEMmap1 ,vmem1 ,0 )
#include "ace.h"
#if NACE > 0
ADDMAP( NACE*32 )
#endif
#if NHD > 0
ADDMAP( NHDC )
#endif
#include "vx.h"
#if NVX > 0
ADDMAP( NVX * 16384/NBPG )
#endif
SYSMAP(VMEMend ,vmemend ,0 )
SYSMAP(VBmap ,vbbase ,CLSIZE )
#if NHD > 0
ADDMAP( NHDC*(MAXPHYS/NBPG+CLSIZE) )
#endif
#if NDK > 0
ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) )
#endif
#if NYC > 0
ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) )
#endif
ADDMAP( NMP*14 )
SYSMAP(eVBmap ,vbend ,0 )
SYSMAP(Usrptmap ,usrpt ,USRPTSIZE+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 */
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
ACBL($MAXMEM*1024-1,$64*1024,r7,1b)
9:
/* clear memory from kernel bss and pages for proc 0 u. and page table */
movab _edata,r6; andl2 $~SYSTEM,r6
movab _end,r5; andl2 $~SYSTEM,r5
#ifdef KADB
subl2 $4,r5
1: clrl (r6); ACBL(r5,$4,r6,1b) # clear just bss
addl2 $4,r5
bbc $6,r11,0f # check RB_KDB
andl3 $~SYSTEM,r9,r5 # skip symbol & string tables
andl3 $~SYSTEM,r9,r6
#endif
0: orl3 $SYSTEM,r5,r9 # convert to virtual address
addl2 $NBPG-1,r9 # roundup to next page
addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5
1: clrl (r6); ACBL(r5,$4,r6,1b)
/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */
orw2 $0x01fff,_trap
orw2 $0x01fff,_syscall
#ifdef FPE
orw2 $0x01fff,_fpemulate
#endif
orw2 $0x01ffc,_panic # for debugging (no r0|r1)
callf $4,_fixctlrmask # setup for autoconfig
/* initialize system page table: scb and int stack writeable */
clrl r2
movab eintstack,r1
andl2 $~SYSTEM,r1
shrl $PGSHIFT,r1,r1 # r1-page number of eintstack
/* make 1st page processor storage read/only, 2nd read/write */
orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
orl3 $PG_V|PG_KW,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 $~PG_PROT,_rsstkmap
orl2 $PG_V|PG_KR,_rsstkmap
/* make kernel text space read-only */
movab _etext+NBPG-1,r1
andl2 $~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 */
andl3 $~SYSTEM,r9,r1
shrl $PGSHIFT,r1,r1
1: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]
aoblss r1,r2,1b
/* 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
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 */
andl3 $~SYSTEM,r9,r6 # convert to physical
andl2 $~(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 r9,PCB_R9(r1) # r9 obtained from boot
movl r10,PCB_R10(r1) # r10 obtained from boot
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
shll $PGSHIFT,r3,r3
mtpr r3,$PCBB # first pcbb (physical)
/* go to kernel mode */
ldpctx
rei # Actually next instruction:
/* put signal trampoline code in u. area */
1: movab sigcode,r0
movab _u+PCB_SIGC,r1
movl $19,r2
movblk
/* save boot device in global _bootdev */
movl r10,_bootdev
/* save reboot flags in global _boothowto */
movl r11,_boothowto
#ifdef KADB
/* save end of symbol & string table in global _bootesym */
subl3 $NBPG-1,r9,_bootesym
#endif
/* calculate firstaddr, and call main() */
andl3 $~SYSTEM,r9,r0
shrl $PGSHIFT,r0,-(sp)
addl2 $UPAGES+1,(sp) # first physical unused page
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
/*
* Mask for saving/restoring registers on entry to
* a user signal handler. Space for the registers
* is reserved in sendsig, so beware if you want
* to change the mask.
*/
#define SIGREGS (R0|R1|R2|R3|R4|R5)
.align 2
.globl sigcode
sigcode:
storer $SIGREGS,16(sp) # save volatile registers
calls $4*3+4,*12(sp) # params pushed by sendsig for handler
loadr $SIGREGS,4(sp) # restore volatile registers
movab 24(sp),fp # use parameter list set up in sendsig
kcall $SYS_sigreturn # cleanup mask and onsigstack
halt # sigreturn does not return!
.globl _icode
.globl _initflags
.globl _szicode
/*
* Icode is copied out to process 1 to exec /etc/init.
* If the exec fails, process 1 exits.
*/
.align 2
_icode:
/* try /sbin/init */
pushab b`argv1-l0(pc)
l0: pushab b`init1-l1(pc)
l1: pushl $2
movab (sp),fp
kcall $SYS_execv
/* try /etc/init */
pushab b`argv2-l2(pc)
l2: pushab b`init2-l3(pc)
l3: pushl $2
movab (sp),fp
kcall $SYS_execv
/* give up */
pushl r0
pushl $1
movab (sp),fp
kcall $SYS_exit
init1: .asciz "/sbin/init"
init2: .asciz "/etc/init"
.align 2
_initflags:
.long 0
argv1: .long init1+6-_icode
.long _initflags-_icode
.long 0
argv2: .long init2+5-_icode
.long _initflags-_icode
.long 0
_szicode:
.long _szicode-_icode
/*
* 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.
*/
ENTRY(badaddr, R3|R4)
mfpr $IPL,r1
mtpr $HIGH,$IPL
movl _scb+SCB_BUSERR,r2
movl 4(fp),r3
movl 8(fp),r4
movab 9f,_scb+SCB_BUSERR
bbc $0,r4,1f; tstb (r3)
1: bbc $1,r4,1f; tstw (r3)
1: bbc $2,r4,1f; tstl (r3)
1: clrl r0
2: movl r2,_scb+SCB_BUSERR
mtpr r1,$IPL
ret
/*
* wbadaddr(addr, len, value)
* see if write of value to 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.
*/
ENTRY(wbadaddr, R3|R4)
mfpr $IPL,r1
mtpr $HIGH,$IPL
movl _scb+SCB_BUSERR,r2
movl 4(fp),r3
movl 8(fp),r4
movab 9f,_scb+SCB_BUSERR
bbc $0,r4,1f; movb 15(fp), (r3)
1: bbc $1,r4,1f; movw 14(fp), (r3)
1: bbc $2,r4,1f; movl 12(fp), (r3)
1: movl $30000,r0 # delay for error interrupt
1: decl r0
jneq 1b
2: movl r2,_scb+SCB_BUSERR # made it w/o machine checks; r0 is 0
mtpr r1,$IPL
ret
.align 2
9: # 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.
*/
ENTRY(badcyaddr, 0)
mfpr $IPL,r1
mtpr $HIGH,$IPL
clrl r2
movab 2f,nofault
movob $-1, *4(fp)
1: aobleq $1000, r2, 1b
clrl nofault # made it w/o bus error
clrl r0
jbr 3f
2: movl $1,r0
3: mtpr r1,$IPL
ret
/*
* peek(addr)
* fetch word and catch any bus error
*/
ENTRY(peek, 0)
mfpr $IPL,r1
mtpr $0x18,$IPL # not reentrant
movl 4(fp),r2
movab 1f,nofault
movw (r2),r0
clrl nofault
andl2 $0xffff,r0
jbr 2f
1: movl $-1,r0 # bus error
2: mtpr r1,$IPL
ret
/*
* poke(addr, val)
* write word and catch any bus error
*/
ENTRY(poke, R3)
mfpr $IPL,r1
mtpr $0x18,$IPL # not reentrant
movl 4(fp),r2
movl 8(fp),r3
clrl r0
movab 1f,nofault
movw r3,(r2)
clrl nofault
jbr 2f
1: movl $-1,r0 # bus error
2: mtpr r1,$IPL
ret
/*
* Copy a potentially overlapping block of memory.
*
* ovbcopy(src, dst, count)
* caddr_t src, dst; unsigned count;
*/
ENTRY(ovbcopy, R3|R4)
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
/*
* Copy a null terminated string from the user address space into
* the kernel address space.
*
* copyinstr(fromaddr, toaddr, maxlength, &lencopied)
*/
ENTRY(copyinstr, 0)
movl 12(fp),r5 # r5 = max length
jlss 5f
movl 8(fp),r4 # r4 = kernel address
movl 4(fp),r0 # r0 = user address
andl3 $(NBPG*CLSIZE-1),r0,r2 # r2 = bytes on first page
subl3 r2,$(NBPG*CLSIZE),r2
1:
cmpl r5,r2 # r2 = min(bytes on page, length left);
jgeq 2f
movl r5,r2
2:
prober $1,(r0),r2 # bytes accessible?
jeql 5f
subl2 r2,r5 # update bytes left count
movl r2,r3 # r3 = saved count
movl r0,r1
cmps3 # check for null
tstl r2
jneq 3f
subl2 r3,r0 # back up r0
movl r4,r1
movl r3,r2
movblk # copy in next piece
movl r1,r4
movl $(NBPG*CLSIZE),r2 # check next page
tstl r5 # run out of space?
jneq 1b
movl $ENOENT,r0 # set error code and return
jbr 6f
3:
tstl 16(fp) # return length?
beql 4f
subl3 r5,12(fp),r5 # actual len = maxlen - unused pages
subl2 r2,r5 # - unused on this page
addl3 $1,r5,*16(fp) # + the null byte
4:
movl r4,r1
subl3 r2,r3,r2 # calc char cnt
subl2 r2,r0 # back up r0
incl r2 # add on null byte
movblk # copy last piece
clrl r0
ret
5:
movl $EFAULT,r0
6:
tstl 16(fp)
beql 7f
subl3 r5,12(fp),*16(fp)
7:
ret
/*
* Copy a null terminated string from the kernel
* address space to the user address space.
*
* copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
*/
ENTRY(copyoutstr, 0)
movl 12(fp),r5 # r5 = max length
jlss 5f
movl 4(fp),r0 # r0 = kernel address
movl 8(fp),r4 # r4 = user address
andl3 $(NBPG*CLSIZE-1),r4,r2 # r2 = bytes on first page
subl3 r2,$(NBPG*CLSIZE),r2
1:
cmpl r5,r2 # r2 = min(bytes on page, length left);
jgeq 2f
movl r5,r2
2:
probew $1,(r4),r2 # bytes accessible?
jeql 5f
subl2 r2,r5 # update bytes left count
movl r2,r3 # r3 = saved count
movl r0,r1
/*
* This is a workaround for a microcode bug that causes
* a trap type 9 when cmps3/movs3 touches the last byte
* on a valid page immediately followed by an invalid page.
*/
#ifdef good_cmps3
cmps3 # check for null
tstl r2
jneq 3b
#else
decl r2
beql 9f # cannot handle case of r2 == 0!
cmps3 # check for null up to last byte
9:
incl r2
cmpl $1,r2 # get to last byte on page?
bneq 3b
tstb (r0) # last byte on page null?
beql 3b
incl r0 # not null, so bump pointer
#endif not good_cmps3
subl2 r3,r0 # back up r0
movl r4,r1
movl r3,r2
movblk # copy out next piece
movl r1,r4
movl $(NBPG*CLSIZE),r2 # check next page
tstl r5 # run out of space?
jneq 1b
movl $ENOENT,r0 # set error code and return
jbr 6b
5:
clrl *$0 # this should never execute, if it does
movl $EFAULT,r0 # save me a core dump (mkm - 9/87)
6:
tstl 16(fp)
beql 7f
subl3 r5,12(fp),*16(fp)
7:
ret
/*
* Copy a null terminated string from one point to another in
* the kernel address space.
*
* copystr(fromaddr, toaddr, maxlength, &lencopied)
*/
ENTRY(copystr, 0)
movl 12(fp),r3 # r3 = max length
jlss 5b
movl 4(fp),r0 # r0 = src address
movl 8(fp),r4 # r4 = dest address
clrl r5 # r5 = bytes left
movl r3,r2 # r2 = max bytes to copy
movl r0,r1
cmps3 # check for null
tstl r2
jneq 3b
subl2 r3,r0 # back up r0
movl r4,r1
movl r3,r2
movblk # copy next piece
movl $ENOENT,r0 # set error code and return
jbr 6b
/*
* Copy a block of data from the user address space into
* the kernel address space.
*
* copyin(fromaddr, toaddr, count)
*/
ENTRY(copyin, 0)
movl 12(fp),r0 # copy length
blss 9f
movl 4(fp),r1 # copy user address
cmpl $(CLSIZE*NBPG),r0 # probing one page or less ?
bgeq 2f # yes
1:
prober $1,(r1),$(CLSIZE*NBPG) # bytes accessible ?
beql 9f # no
addl2 $(CLSIZE*NBPG),r1 # incr user address ptr
_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop
2:
prober $1,(r1),r0 # bytes accessible ?
beql 9f # no
MOVC3(4(fp),8(fp),12(fp))
clrl r0
ret
9:
movl $EFAULT,r0
ret
/*
* Copy a block of data from the kernel
* address space to the user address space.
*
* copyout(fromaddr, toaddr, count)
*/
ENTRY(copyout, 0)
movl 12(fp),r0 # get count
blss 9b
movl 8(fp),r1 # get user address
cmpl $(CLSIZE*NBPG),r0 # can do in one probew?
bgeq 2f # yes
1:
probew $1,(r1),$(CLSIZE*NBPG) # bytes accessible?
beql 9b # no
addl2 $(CLSIZE*NBPG),r1 # increment user address
_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop
2:
probew $1,(r1),r0 # bytes accessible?
beql 9b # no
MOVC3(4(fp),8(fp),12(fp))
clrl r0
ret
/*
* non-local goto's
*/
#ifdef notdef
ENTRY(setjmp, 0)
movl 4(fp),r0
movl (fp),(r0); addl2 $4,r0 # save fp
movl -8(fp),(r0) # save pc
clrl r0
ret
#endif
ENTRY(longjmp, 0)
movl 4(fp),r0
movl (r0),newfp; addl2 $4,r0 # must save parameters in memory
movl (r0),newpc # as all regs may be clobbered.
1:
cmpl fp,newfp # are we there yet?
bgequ 2f # yes
moval 1b,-8(fp) # redirect return pc to us!
ret # pop next frame
2:
beql 3f # did we miss our frame?
pushab 4f # yep ?!?
callf $8,_panic
3:
movl newpc,r0 # all done, just return
jmp (r0) # to setjmp `ret'
.data
newpc: .space 4
newfp: .space 4
4: .asciz "longjmp"
.text
/*
* setjmp that saves all registers as the call frame may not
* be available to recover them in the usual manner by longjmp.
* Called before swapping out the u. area, restored by resume()
* below.
*/
ENTRY(savectx, 0)
movl 4(fp),r2
storer $0x1ff8,(r2); addl2 $40,r2 # r3-r12
movl (fp),(r2); addl2 $4,r2 # fp
movab 8(fp),(r2); addl2 $4,r2 # sp
movl -8(fp),(r2) # pc
clrl r0
ret
#ifdef KADB
/*
* C library -- reset, setexit
*
* reset(x)
* will generate a "return" from
* the last call to
* setexit()
* by restoring r2 - r12, fp
* and doing a return.
* The returned value is x; on the original
* call the returned value is 0.
*/
ENTRY(setexit, 0)
movab setsav,r0
storer $0x1ffc, (r0)
movl (fp),44(r0) # fp
moval 4(fp),48(r0) # sp
movl -8(fp),52(r0) # pc
clrl r0
ret
ENTRY(reset, 0)
movl 4(fp),r0 # returned value
movab setsav,r1
loadr $0x1ffc,(r1)
movl 44(r1),fp
movl 48(r1),sp
jmp *52(r1)
.data
.align 2
setsav: .space 14*4
.text
#endif
.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
*/
ENTRY(setrq, 0)
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().
*/
ENTRY(remrq, 0)
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"
/*
* 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
.align 2
_masterpaddr: .long 0
.text
sw0: .asciz "swtch"
/*
* When no processes are on the runq, swtch branches to idle
* to wait for something to come ready.
*/
.globl Idle
Idle: idle:
movl $1,_noproc
mtpr $0,$IPL # must allow interrupts here
1:
tstl _whichqs # look for non-empty queue
bneq sw1
brb 1b
badsw: pushab sw0
callf $8,_panic
/* NOTREACHED */
.align 2
/*
* swtch(), using fancy tahoe instructions
*/
ENTRY(swtch, 0)
movl (fp),fp # prepare for rei
movl (sp),4(sp) # saved pc
tstl (sp)+
movpsl 4(sp)
incl _cnt+V_SWTCH
sw1: ffs _whichqs,r0 # look for non-empty queue
blss idle # if none, idle
mtpr $0x18,$IPL # lock out all so _whichqs==_qs
bbc r0,_whichqs,sw1 # proc moved via interrupt
shal $1,r0,r1
moval _qs[r1],r1
movl (r1),r2 # r2 = p = highest pri process
remque *(r1)
bvs badsw # make sure something was there
bneq sw2
shal r0,$1,r1
mcoml r1,r1
andl2 r1,_whichqs # no more procs in this queue
sw2:
clrl _noproc
clrl _runrun
#ifdef notdef
tstl P_WCHAN(r2) ## firewalls
bneq badsw ##
cmpb P_STAT(r2),$SRUN ##
bneq badsw ##
#endif
clrl P_RLINK(r2) ##
movl *P_ADDR(r2),r0
#ifdef notdef
cmpl r0,_masterpaddr # resume of current proc is easy
beql res0
#endif
movl r0,_masterpaddr
shal $PGSHIFT,r0,r0 # r0 = pcbb(p)
brb swresume
/*
* resume(pf)
*/
ENTRY(resume, 0)
shal $PGSHIFT,4(fp),r0 # r0 = pcbb(pf)
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
REST_ACC # restore original accumulator
svpctx
mtpr r0,$PCBB
ldpctx
movl _u+PCB_CMAP2,_CMAP2 # yech
mtpr $_CADDR2,$TBIS
res0:
movl _u+U_PROCP,r2 # r2 = u.u_procp
tstl P_CKEY(r2) # does proc have code key?
bneq 1f
callf $4,_getcodekey # no, give him one
movl _u+U_PROCP,r2 # r2 = u.u_procp
movl r0,P_CKEY(r2)
1:
tstl P_DKEY(r2) # does proc have data key?
bneq 1f
callf $4,_getdatakey # no, give him one
movl _u+U_PROCP,r2 # r2 = u.u_procp
movl r0,P_DKEY(r2)
1:
mtpr P_CKEY(r2),$CCK # set code cache key
mtpr P_DKEY(r2),$DCK # set data cache key
tstl _u+PCB_SSWAP
bneq res1
rei
res1: # longjmp to saved context
movl _u+PCB_SSWAP,r2
clrl _u+PCB_SSWAP
loadr $0x3ff8,(r2); addl2 $44,r2 # restore r3-r13 (r13=fp)
movl (r2),r1; addl2 $4,r2 # fetch previous sp ...
movab (sp),r0 # ... and current sp and
cmpl r1,r0 # check for credibility,
bgequ 1f # if further up stack ...
pushab 2f; callf $8,_panic # ... panic
/*NOTREACHED*/
1: # sp ok, complete return
movl r1,sp # restore sp
pushl $PSL_PRVMOD # kernel mode, ipl 0
pushl (r2) # return address
rei
2: .asciz "ldctx"
/*
* {fu,su},{byte,word}
*/
ENTRY(fuword, 0)
movl 4(fp), r1
prober $1,(r1),$4 # check access
beql fserr # page unreadable
bitl $1,r1 # check byte alignment
bneq 2f # odd, do byte-word-byte
bitl $2,r1 # check word alignment
bneq 1f # odd, do in 2 words
movl (r1),r0 # move longword
ret
1:
movw (r1),r0 # move two words
shal $16,r0,r0
movzwl 2(r1),r1 # orw2 sign extends
orl2 r1,r0
ret
2:
movb (r1),r0 # move byte-word-byte
shal $24,r0,r0
movzwl 1(r1),r2 # orw2 sign extends
shal $8,r2,r2
movzbl 3(r1),r1 # orb2 sign extends
orl2 r2,r1
orl2 r1,r0
ret
fserr:
mnegl $1,r0
ret
ENTRY(fubyte, 0)
prober $1,*4(fp),$1
beql fserr
movzbl *4(fp),r0
ret
ENTRY(suword, 0)
movl 4(fp), r0
probew $1,(r0),$4 # check access
beql fserr # page unwritable
bitl $1,r0 # check byte alignment
bneq 1f # odd byte boundary
bitl $2,r0 # check word alignment
beql 2f # longword aligned
movw 8(fp),(r0) # move two words
movw 10(fp),2(r0)
jbr 3f
1:
movb 8(fp),(r0)
movb 9(fp),1(r0)
movb 10(fp),2(r0)
movb 11(fp),3(r0)
jbr 3f
2:
movl 8(fp),(r0)
3:
clrl r0
ret
ENTRY(subyte, 0)
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
*/
ENTRY(copyseg, 0)
orl3 $PG_V|PG_KW,8(fp),_CMAP2
mtpr $_CADDR2,$TBIS # invalidate entry for copy
MOVC3(4(fp),$_CADDR2,$NBPG)
ret
/*
* Clear a page of memory. The page frame is specified.
*
* clearseg(pf);
*/
ENTRY(clearseg, 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
/*
* Check user mode read/write access.
*
* useracc(addr, count, mode)
* caddr_t addr; int count, mode;
* mode = 0 write access
* mode = 1 read access
*/
ENTRY(useracc, 0)
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 $(CLSIZE*NBPG),r1 # can we do it in one probe ?
bgeq uaw2 # yes
uaw1:
probew r2,(r0),$(CLSIZE*NBPG)
beql uaerr # no access
addl2 $(CLSIZE*NBPG),r0
_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1)
uaw2:
probew r2,(r0),r1
beql uaerr
movl $1,r0
ret
userar:
cmpl $(CLSIZE*NBPG),r1
bgeq uar2
uar1:
prober r2,(r0),$(CLSIZE*NBPG)
beql uaerr
addl2 $(CLSIZE*NBPG),r0
_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1)
uar2:
prober r2,(r0),r1
beql uaerr
movl $1,r0
ret
uaerr:
clrl r0
ret
/*
* Check kernel mode read/write access.
*
* kernacc(addr, count, mode)
* caddr_t addr; int count, mode;
* mode = 0 write access
* mode = 1 read access
*/
ENTRY(kernacc, 0)
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, delta)
* long pc; short delta; 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
* }
*/
ENTRY(addupc, 0)
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
/*
* scanc(size, cp, table, mask)
*/
ENTRY(scanc, R3|R4)
movl 8(fp),r0 # r0 = cp
addl3 4(fp),r0,r2 # end = &cp[size]
movl 12(fp),r1 # r1 = table
movb 19(fp),r4 # r4 = mask
decl r0 # --cp
jbr 0f # just like Fortran...
1: # do {
movzbl (r0),r3
bitb r4,(r1)[r3] # if (table[*cp] & mask)
jneq 2f # break;
0: aoblss r2,r0,1b # } while (++cp < end);
2:
subl3 r0,r2,r0; ret # return (end - cp);
/*
* skpc(mask, size, cp)
*/
ENTRY(skpc, 0)
movl 12(fp),r0 # r0 = cp
addl3 8(fp),r0,r1 # r1 = end = &cp[size];
movb 7(fp),r2 # r2 = mask
decl r0 # --cp;
jbr 0f
1: # do
cmpb (r0),r2 # if (*cp != mask)
jneq 2f # break;
0: aoblss r1,r0,1b # while (++cp < end);
2:
subl3 r0,r1,r0; ret # return (end - cp);
/*
* locc(mask, size, cp)
*/
ENTRY(locc, 0)
movl 12(fp),r0 # r0 = cp
addl3 8(fp),r0,r1 # r1 = end = &cp[size]
movb 7(fp),r2 # r2 = mask
decl r0 # --cp;
jbr 0f
1: # do
cmpb (r0),r2 # if (*cp == mask)
jeql 2f # break;
0: aoblss r1,r0,1b # while (++cp < end);
2:
subl3 r0,r1,r0; ret # return (end - cp);
#ifdef ALIGN
#include "../tahoealign/align.h"
.globl _alignment
/*
* There's an intimate relationship between this piece of code
* and the alignment emulation code (especially the layout
* of local variables in alignment.c! Don't change unless
* you update both this, alignment.h and alignment.c !!
*/
non_aligned:
orb2 $EMULATEALIGN,_u+U_EOSYS
incl _cnt+V_TRAP
incl _cnt+V_ALIGN # count emulated alignment traps
moval 4(sp),_user_psl
SAVE_FPSTAT(4) # Also zeroes out ret_exception !
pushl $0 # ret_addr
pushl $0 # ret_code
mfpr $USP,-(sp) # user sp
callf $4,_alignment # call w/o parms so regs may be modified
/*
* We return here after a successful emulation or an exception.
* The registers have been restored and we must not alter them
* before returning to the user.
*/
2: mtpr (sp)+,$USP # restore user sp
tstl 8(sp) # Any exception ?
bneq got_excp # Yes, reflect it back to user.
moval 8(sp),sp # pop 2 zeroes pushed above
REST_FPSTAT
xorb2 $EMULATEALIGN,_u+U_EOSYS
bitl $PSL_T,4(sp) # check for trace bit set
beql 9f
CHECK_SFE(4)
pushl $0
SAVE_FPSTAT(8)
TRAP(TRCTRAP)
9: rei
got_excp: # decode exception
casel 8(sp),$ILL_ADDRMOD,$ALIGNMENT
.align 1
L1:
.word ill_addrmod-L1
.word ill_access-L1
.word ill_oprnd-L1
.word arithmetic-L1
.word alignment-L1
brw alignment # default - shouldn't come here at all !
ill_addrmod: # No other parameters. Set up stack as
moval 8(sp),sp # the HW would do it in a real case.
REST_FPSTAT
jbr _Xresadflt
ill_oprnd:
moval 8(sp),sp
REST_FPSTAT
jbr _Xresopflt
alignment:
moval 8(sp),sp
REST_FPSTAT
jbr align_excp # NB: going to _Xalignflt would cause loop
ill_access:
/*
* Must restore accumulator w/o modifying sp and w/o using
* registers. Solution: copy things needed by REST_FPSTAT.
*/
pushl 20(sp) # The flags longword
pushl 20(sp) # acc_low
pushl 20(sp) # acc_high
pushl 20(sp) # ret_exception ignored by REST_FPSTAT
REST_FPSTAT # Back where we were with the sp !
movl (sp),16(sp) # code for illegal access
movl 4(sp),20(sp) # original virtual address
moval 16(sp),sp # Just like the HW would set it up
jbr _Xprotflt
arithmetic: # same trickery as above
pushl 20(sp) # The flags longword
pushl 20(sp) # acc_low
pushl 20(sp) # acc_high
pushl 20(sp) # ret_exception ignored by REST_FPSTAT
REST_FPSTAT # Back where we were with the sp !
movl (sp),20(sp) # code for arithmetic exception
moval 20(sp),sp # Just like the HW would set it up
jbr _Xarithtrap
#endif
SCBVEC(hdintr0):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*0)
pushl $0
callf $8,_hdintr
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(hdintr1):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*1)
pushl $1
callf $8,_hdintr
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vdintr0):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*2)
pushl $0
callf $8,_vdintr
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vdintr1):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*3)
pushl $1
callf $8,_vdintr
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vdintr2):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*4)
pushl $2
callf $8,_vdintr
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vackint0):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*5)
pushl $0
callf $8,_vackint
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vcmdrsp0):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*6)
pushl $0
callf $8,_vcmdrsp
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vunsol0):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*7)
pushl $0
callf $8,_vunsol
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vackint1):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*8)
pushl $1
callf $8,_vackint
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vcmdrsp1):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*9)
pushl $1
callf $8,_vcmdrsp
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(vunsol1):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*10)
pushl $1
callf $8,_vunsol
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
SCBVEC(exintr0):
CHECK_SFE(4)
SAVE_FPSTAT(4)
PUSHR
incl _fltintrcnt+(4*11)
pushl $0
callf $8,_exintr
incl _cnt+V_INTR
POPR
REST_FPSTAT
rei
.globl _intrnames
.globl _eintrnames
.data
_intrnames:
.asciz "clock"
.asciz "cnr"
.asciz "cnx"
.asciz "rmtr"
.asciz "rmtx"
.asciz "buserr"
.asciz "hd0"
.asciz "hd1"
.asciz "vd0"
.asciz "vd1"
.asciz "vd2"
.asciz "vack0"
.asciz "vcmdrsp0"
.asciz "vunsol0"
.asciz "vack1"
.asciz "vcmdrsp1"
.asciz "vunsol1"
.asciz "ex0"
_eintrnames:
.globl _intrcnt
.globl _eintrcnt
.align 2
_intrcnt:
.space 4 * 6
_fltintrcnt:
.space 4 * 12
_eintrcnt:
.text
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.