File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / tahoe / locore.1.s
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (6 years, 11 months ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
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

unix.superglobalmegacorp.com

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