File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / tahoe / locore.s
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:30:04 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

/*	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 "../machine/fp.h"
/*---------------- Alignment code -------------------*/
#include "../machine/alignment.h"
/*---------------- Alignment code -------------------*/

#include "../h/errno.h"

.data
.align 2
.text
	.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	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

	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 	*$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*4)+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.

#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:	;

#define PUSHBPAR	pushab	6*4(sp) /* Push address of buserr paramters */
#define BPAR1		28		/* Offset to first hardware parameter */

SCBVEC(buserr):
	CHECK_SFE(12)
	SAVE_FPSTAT(12);
	PUSHR
	andl3	BPAR1(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:
	PUSHBPAR	# Pointer to parameters
	callf	$8,_buserror
	POPR
	REST_FPSTAT;
	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;
	movpsl	r0
	shrl	$16, r0,-(sp) 
	andl2	$0x1f, (sp)
	PRINTF(2, "******* Undefined interrupt at ipl 0x%x *******\n");
	POPR;
	rei

#include "../net/netisr.h"
	.globl	_netisr
SCBVEC(netintr):
	CHECK_SFE(4)
	SAVE_FPSTAT(4)
	PUSHR

	bbc	$NETISR_RAW,_netisr,1f
	andl2	$(0!(1<<NETISR_RAW)),_netisr	
	callf	$4,_rawintr	
1:
#ifdef INET
#include "../netinet/in_systm.h"
	bbc	$NETISR_IP,_netisr,1f	
	andl2	$(0!(1<<NETISR_IP)),_netisr
	callf	$4,_ipintr	
1:
#endif
#ifdef NS
	bbc	$NETISR_NS,_netisr,1f	
	andl2	$(0!(1<<NETISR_NS)),_netisr
	callf	$4,_nsintr	
1:
#endif
	POPR; 
	REST_FPSTAT
	rei
SCBVEC(soft15):
SCBVEC(soft14):
SCBVEC(soft13):
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(1, "******* Undefined software interrupt *******\n")
	POPR;
	rei

#ifdef SIMIO
SCBVEC(soft2):
#endif
SCBVEC(cnrint):
	CHECK_SFE(4)
	SAVE_FPSTAT(4);PUSHR; 
	pushl $CPCONS; callf $8,_cnrint; POPR; incl _cnt+V_INTR;
	REST_FPSTAT; rei
#ifdef SIMIO
SCBVEC(soft3):
#endif
SCBVEC(cnxint):
	CHECK_SFE(4)
	SAVE_FPSTAT(4);PUSHR; 
	pushl $CPCONS; callf $8,_cnxint; POPR; REST_FPSTAT;
	incl _cnt+V_INTR; rei
SCBVEC(rmtrint):
	CHECK_SFE(4)
	SAVE_FPSTAT(4); PUSHR; 
	pushl $CPREMOT; callf $8,_cnrint; POPR; REST_FPSTAT;
	incl _cnt+V_INTR; rei
SCBVEC(rmtxint):
	CHECK_SFE(4)
	SAVE_FPSTAT(4); PUSHR; 
	pushl $CPREMOT; callf $8,_cnxint; POPR; REST_FPSTAT;
	incl _cnt+V_INTR; rei
#ifdef SIMIO
SCBVEC(soft9):
#endif

#define PUSHPCPSL	pushl 5*4+2*4(sp); pushl 5*4+2*4(sp);

SCBVEC(hardclock):
	CHECK_SFE(4)
	SAVE_FPSTAT(4)
	PUSHR
	PUSHPCPSL				# push pc and psl
	callf $12,_hardclock			# hardclock(pc,psl)
	POPR;
	REST_FPSTAT
	incl	_cnt+V_INTR		## temp so not to break vmstat -= HZ
	rei
SCBVEC(softclock):
	CHECK_SFE(4)
	SAVE_FPSTAT(4)
	PUSHR
	PUSHPCPSL				# push pc and psl
	callf $12,_softclock			# softclock(pc,psl)
	POPR; 
	REST_FPSTAT
	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;
	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(tracep):
	CHECK_SFE(4)
	pushl $0;
	SAVE_FPSTAT(8)
	TRAP(TRCTRAP)
SCBVEC(alignflt):
/*---------------- Alignment code -------------------*/
/*	CHECK_SFE(4)				     */
	bitl	$PSL_CURMOD,4(sp)
	jeql	align_excp		# Can't emulate for kernel mode !
	jmp	non_aligned		# Only emulated for user mode.
align_excp:
/*---------------- Alignment code -------------------*/
	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
	.globl	_fpemulate
	CHECK_SFE(16)
	SAVE_FPSTAT(16)
	callf	$4,_fpemulate
	REST_FPSTAT
	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	$1,(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, an 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, an fp stuff
	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(ACE0map	,ace0utl	,(ACEBPTE+1)	)
	SYSMAP(ACE1map	,ace1utl	,(ACEBPTE+1)	)
  	SYSMAP(ENP0map	,enp0utl	,128		)
  	SYSMAP(ENP1map	,enp1utl	,128		)
	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(VD0map	,vd0utl		,(MAXBPTE+1)	)
	SYSMAP(VD1map	,vd1utl		,(MAXBPTE+1)	)
	SYSMAP(VD2map	,vd2utl		,(MAXBPTE+1)	)
	SYSMAP(VD3map	,vd3utl		,(MAXBPTE+1)	)
	SYSMAP(VD4map	,vd4utl		,(MAXBPTE+1)	)
	SYSMAP(VD5map	,vd5utl		,(MAXBPTE+1)	)
	SYSMAP(VD6map	,vd6utl		,(MAXBPTE+1)	)
	SYSMAP(VD7map	,vd7utl		,(MAXBPTE+1)	)
	SYSMAP(CY0map	,cy0utl		,(TBUFSIZ+1)	)
	SYSMAP(CY1map	,cy1utl		,(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)
	SYSMAP(Msgmap	,msgutl		,MSGMAPPTE)
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
	brb	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' */
/* force panic() to save r0-r12 for easier debugging */
	orw2	$0x01fff,_trap
	orw2	$0x01fff,_syscall
	orw2	$0x01fff,_fpemulate
	orw2	$0x01fff,_panic

/*---------------- Alignment code -------------------*/
	orw2	$0x01fff,_alignment
/*---------------- Alignment code -------------------*/

/* 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
	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),$1		# first byte accessible ?
	beql	ersb			# no
	addl2	r0,r1			# get last byte's address
	decl	r1
	prober	$1,(r1),$1		# last byte 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),$1		# first byte accessible?
	beql	ersb			# no
	addl2	r0,r1			# get last byte's address
	decl	r1
	probew	$1,(r1),$1		# last byte 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... */

	.data
	.globl	_prevpcb
_prevpcb:
	.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
	REST_ACC			# restore original accumulator
	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:
/*
 * Now we have to care about code and data keys.
 * 2 functions may be called, so r0 and r1 must be
 * saved across the 'callf'. Also, r2 is used as index
 * since r1 may be changed by the functions (just a
 * precaution).
 */
	PUSHR				# ro and r1
	pushl	r2
	movl	_u+U_PROCP,r2		# r2 = & proc[?]
	tstl	P_CKEY(r2)		# does he have a code key ?
	bneq	ckey_ok
	callf	$4,_getcodekey		# no, we have to give him one.
	movl	r0,P_CKEY(r2)
ckey_ok:
	tstl	P_DKEY(r2)		# same stuff for data key
	bneq	dkey_ok
	callf	$4,_getdatakey
	movl	r0,P_DKEY(r2)
dkey_ok:
	mtpr	P_CKEY(r2),$CCK
	mtpr	P_DKEY(r2),$DCK
	movl	(sp)+,r2		# restore his registers
	POPR
	rei

/*
 * {fu,su},{byte,word}
 */
	.globl	_fuiword
	.globl	_fuword
_fuiword:
_fuword:
	.word	0x4			# save r2
	movl	4(fp),r1
	prober	$1,(r1),$1		# check access of first byte
	beql	fserr			# page unreadable
	prober	$1,3(r1),$1		# check access of last byte
	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			# even, 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

	.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
	movl	4(fp),r0
	probew	$1,(r0),$1		# check access of first byte
	beql	fserr			# page unwritable
	probew	$1,3(r0),$1		# check access of last byte
	beql	fserr			# page unwritable
	bitl	$1,r0			# check byte alignment
	bneq	1f			# odd byte boundary
	bitl	$2,r0			# check word alignment
	beql	2f			# longword boundary
	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

	.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	0x4
	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),$1		# check first byte
	beql	uaerr
	addl2	r1,r0			# get the address of the last byte
	decl	r0
	probew	r2,(r0),$1		# check last byte
	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),$1		# check first byte
	beql	uaerr
	addl2	r1,r0			# get the address of the last byte
	decl	r0
	prober	r2,(r0),$1		# check last byte
	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],$1	# first byte of counter accessible?
	jeql	9f
	addl3	$1,r1,r0	# get address of the last byte
	probew	$1,*0(r2)[r0],$1	# last byte of 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

/*---------------- Alignment code -------------------*/
/*
 * 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 !!
 */

	.globl	_alignment
non_aligned:
	orb2	$EMULATEALIGN,_u+U_EOSYS
	incl	_cnt+V_TRAP
	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	# 0 parameters == don't remove user sp
				#  on return, it may be changed by emulation
				#  so we have to reload it by hand !

/*
# We're back either after correct emulation or after an exception.
# The registers now are the user's original registers, so take care
#	not to ruin them before the 'rei' or whatever !
*/
2:	mtpr	(sp)+,$USP	# restore user sp. HW sp points to ret_code
	tstl	8(sp)		# Any exception ?
	bneq	got_excp	# Yes, reflect it back to user.
	moval	8(sp),sp	# pop the 2 zeroes we pushed
	REST_FPSTAT
	xorb2	$EMULATEALIGN,_u+U_EOSYS
/*
 * Check for trace bit set.
 */
	bitl	$PSL_T,4(sp)
	beql	9f
	CHECK_SFE(4)
	pushl $0
	SAVE_FPSTAT(8)
	TRAP(TRCTRAP)
9:	rei

got_excp:			# Have to see what exception it was
	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	# Note : don't go to _Xalignflt, this
				#	would cause endless loop !
ill_access:
 /*
 #
 # Now it's tricky. I want to restore the accumulator, but leave the
 #	sp where it is, to keep the ret_code and ret_address!
 #	And I can't use registers! Solution: make a copy of the things
 #	needed by REST_FPSTAT ! Not speedy, but who cares, the process
 #	is just about to go into hyperspace...
 #
 */
	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 for illegal access.
 #
 */
	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

/*---------------- Alignment code -------------------*/

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.