xref: /original-bsd/sys/tahoe/tahoe/locore.s (revision bff07831)
1ab937509Skarels/*
2ab937509Skarels * Copyright (c) 1988 Regents of the University of California.
3ab937509Skarels * All rights reserved.  The Berkeley software License Agreement
4ab937509Skarels * specifies the terms and conditions for redistribution.
5ab937509Skarels *
6*bff07831Sbostic *	@(#)locore.s	7.21 (Berkeley) 09/23/93
7ab937509Skarels */
87479596bSsam
9d357015aSbostic#include "tahoe/include/mtpr.h"
10d357015aSbostic#include "tahoe/include/trap.h"
11d357015aSbostic#include "tahoe/include/psl.h"
12d357015aSbostic#include "tahoe/include/pte.h"
13d357015aSbostic#include "tahoe/tahoe/cp.h"
14d357015aSbostic#include "tahoe/tahoe/mem.h"
15d357015aSbostic#include "tahoe/tahoe/SYS.h"
16ab937509Skarels
17d357015aSbostic#include "tahoe/math/fp.h"
187479596bSsam
19d357015aSbostic#include "sys/errno.h"
20d357015aSbostic#include "sys/syscall.h"
21d357015aSbostic#include "sys/cmap.h"
227479596bSsam
237479596bSsam	.set	HIGH,0x1f		# mask for total disable
247479596bSsam	.set	NISP,3			# number of interrupt stack pages
257479596bSsam	.set	SYSTEM,0xC0000000	# virtual address of system start
26477ef2c3Ssam	.set	PPAGES,0x100000  	# possible pages in P0,P1, etc.
277479596bSsam
287479596bSsam/* ACBL for non-negative '_add' */
297479596bSsam#define ACBL(_limit,_add,_index,_displ) \
307479596bSsam	addl2	_add,_index; \
317479596bSsam	cmpl	_index,_limit; \
327479596bSsam	bleq	_displ
337479596bSsam
347479596bSsam/* _ACBL for negative '_add' */
357479596bSsam#define _ACBL(_limit,_add,_index,_displ) \
367479596bSsam	addl2	_add,_index; \
377479596bSsam	cmpl	_index,_limit; \
387479596bSsam	bgeq	_displ
397479596bSsam
400b8444b9Ssam#define	MOVC3(_srcaddr,_dstaddr,_len) \
417479596bSsam	movl	_srcaddr,r0; \
427479596bSsam	movl	_dstaddr,r1; \
437479596bSsam	movl	_len,r2; \
447479596bSsam	movblk
457479596bSsam
460b8444b9Ssam/* keep address of psl if coming from user mode */
477479596bSsam#define CHECK_SFE(_delta) \
487479596bSsam	bitl	$PSL_CURMOD,_delta(sp); \
497479596bSsam	jeql	1f; \
507479596bSsam	moval	_delta(sp),_user_psl; \
517479596bSsam1:
527479596bSsam
537479596bSsam/*
547479596bSsam * User structure is UPAGES at top of user space.
557479596bSsam */
567479596bSsam	.globl	_u
577479596bSsam	.set	_u,SYSTEM - UPAGES*NBPG
587479596bSsam
597479596bSsam/*
607479596bSsam * Restart stack. Used on power recovery or panic.
617479596bSsam * Takes a core-dump and then halts.
627479596bSsam */
637479596bSsam	.globl	_rsstk
647479596bSsam	.globl	pwfl_stk
650b8444b9Ssam_rsstk:
660b8444b9Ssam	.space	1024-8
670b8444b9Ssampwfl_stk:
680b8444b9Ssam	.space	4
690b8444b9Ssamdumpflag:
700b8444b9Ssam	.space	4
717479596bSsam
727479596bSsam	.globl	_intstack
737479596bSsam_intstack:
747479596bSsam	.space	NISP*NBPG
757479596bSsameintstack:
767479596bSsam
770b8444b9Ssam/*
780b8444b9Ssam * Power failure storage block and
790b8444b9Ssam * macros for saving and restoring.
800b8444b9Ssam */
810b8444b9Ssam#define	POWERFAIL(id,longs) \
820b8444b9Ssam	.globl	pwfl_/**/id \
830b8444b9Ssampwfl_/**/id: .space longs*4
847479596bSsam	.data
850b8444b9Ssam	POWERFAIL(r0,	14)		# r0-r13
860b8444b9Ssam	POWERFAIL(sp,	1)		# r14
870b8444b9Ssam	POWERFAIL(SCBB,	1)		# system control block base
880b8444b9Ssam	POWERFAIL(SBR,	1)		# system pte base
890b8444b9Ssam	POWERFAIL(SLR,	1)		# system pte length
900b8444b9Ssam	POWERFAIL(P0BR,	1)		# p0 pte base
910b8444b9Ssam	POWERFAIL(P0LR,	1)		# p0 pte length
920b8444b9Ssam	POWERFAIL(P1BR,	1)		# p1 pte base
930b8444b9Ssam	POWERFAIL(P1LR,	1)		# p1 pte length
940b8444b9Ssam	POWERFAIL(P2BR,	1)		# p2 pte base
950b8444b9Ssam	POWERFAIL(P2LR,	1)		# p2 pte length
960b8444b9Ssam	POWERFAIL(IPL,	1)		# interrupt priority level
970b8444b9Ssam	POWERFAIL(DCK,	1)		# data cache key
980b8444b9Ssam	POWERFAIL(CCK,	1)		# code cache key
990b8444b9Ssam	POWERFAIL(PCBB,	1)		# process control block base
1000b8444b9Ssam	POWERFAIL(ISP,	1)		# interrupt stack pointer
1010b8444b9Ssam	POWERFAIL(KSP,	1)		# kernel mode stack pointer
1020b8444b9Ssam	POWERFAIL(USP,	1)		# user mode stack pointer
1030b8444b9Ssam	POWERFAIL(MME,	1)		# memory management enable
1040b8444b9Ssam	POWERFAIL(PSL,	1)		# processor status longword
1050b8444b9Ssam
1060b8444b9Ssam/*
1070b8444b9Ssam * Save current state in power fail storage block.
1080b8444b9Ssam */
1090b8444b9Ssam#define	SAVEpwfl() \
1100b8444b9Ssam	movpsl	pwfl_PSL	# Keeps all flags, etc. \
1110b8444b9Ssam	storer	$0x3fff,pwfl_r0	# Saves r0-r13 \
1120b8444b9Ssam	moval	0(sp),pwfl_sp	# Saves sp (=r14) \
1130b8444b9Ssam	mfpr	$SBR,pwfl_SBR	# Save all re_loadable registers \
1140b8444b9Ssam	mfpr	$SLR,pwfl_SLR \
1150b8444b9Ssam	mfpr	$P0BR,pwfl_P0BR \
1160b8444b9Ssam	mfpr	$P0LR,pwfl_P0LR \
1170b8444b9Ssam	mfpr	$P1BR,pwfl_P1BR \
1180b8444b9Ssam	mfpr	$P1LR,pwfl_P1LR \
1190b8444b9Ssam	mfpr	$P2BR,pwfl_P2BR \
1200b8444b9Ssam	mfpr	$P2LR,pwfl_P2LR \
1210b8444b9Ssam	mfpr	$IPL,pwfl_IPL \
1220b8444b9Ssam	mfpr	$MME,pwfl_MME \
1230b8444b9Ssam	mfpr	$DCK,pwfl_DCK \
1240b8444b9Ssam	mfpr	$CCK,pwfl_CCK \
1250b8444b9Ssam	mfpr	$PCBB,pwfl_PCBB \
1260b8444b9Ssam	mfpr	$ISP,pwfl_ISP \
1270b8444b9Ssam	mfpr	$SCBB,pwfl_SCBB \
1280b8444b9Ssam	mfpr	$KSP,pwfl_KSP \
1290b8444b9Ssam	mfpr	$USP,pwfl_USP
1300b8444b9Ssam
1310b8444b9Ssam/*
1320b8444b9Ssam * Restore state saved in power fail block and
1330b8444b9Ssam * jmp to location specified after (possibly)
1340b8444b9Ssam * enabling memory management.
1350b8444b9Ssam */
1360b8444b9Ssam#define	RESTOREpwfl(loc) \
1370b8444b9Ssam	loadr	$0x3fff,pwfl_r0	# Restore r0-r13 \
1380b8444b9Ssam	movl	pwfl_sp,sp	# Restore sp (=r14) \
1390b8444b9Ssam	mtpr	pwfl_SCBB,$SCBB \
1400b8444b9Ssam	mtpr	pwfl_SBR,$SBR	# Restore all re_loadable registers \
1410b8444b9Ssam	mtpr	pwfl_SLR,$SLR \
1420b8444b9Ssam	mtpr	pwfl_P0BR,$P0BR \
1430b8444b9Ssam	mtpr	pwfl_P0LR,$P0LR \
1440b8444b9Ssam	mtpr	pwfl_P1BR,$P1BR \
1450b8444b9Ssam	mtpr	pwfl_P1LR,$P1LR \
1460b8444b9Ssam	mtpr	pwfl_P2BR,$P2BR \
1470b8444b9Ssam	mtpr	pwfl_P2LR,$P2LR \
1480b8444b9Ssam	mtpr	pwfl_IPL,$IPL \
1490b8444b9Ssam	mtpr	pwfl_DCK,$DCK \
1500b8444b9Ssam	mtpr	pwfl_CCK,$CCK \
1510b8444b9Ssam	mtpr	pwfl_PCBB,$PCBB \
1520b8444b9Ssam	mtpr	pwfl_ISP,$ISP \
1530b8444b9Ssam	mtpr	pwfl_KSP,$KSP \
1540b8444b9Ssam	mtpr	pwfl_USP,$USP \
1550b8444b9Ssam\
1560b8444b9Ssam	bicpsw	$0xff		# Restore PSW. \
1570b8444b9Ssam	bispsw	pwfl_PSL+2	# Set original bits back (just in case..) \
1580b8444b9Ssam# now go to mapped mode \
1590b8444b9Ssam# Have to change PC to system addresses \
1600b8444b9Ssam	mtpr	$1,$PACC	# Thoroughly clean up caches. \
1610b8444b9Ssam	mtpr	$1,$PADC \
1620b8444b9Ssam	mtpr	$1,$TBIA \
1630b8444b9Ssam	mtpr	pwfl_MME,$MME  	# Restore MME. Last thing to be done. \
1640b8444b9Ssam	jmp 	loc
1657479596bSsam
1667479596bSsam/*
1677479596bSsam * Do a dump.
1687479596bSsam * Called by auto-restart.
1697479596bSsam * May be called manually.
1707479596bSsam */
1717479596bSsam	.align	2
1727479596bSsam	.text
1737479596bSsam	.globl	_Xdoadump
1747479596bSsam	.globl	_doadump
1750b8444b9Ssam_Xdoadump:					# CP comes here after power fail
1760b8444b9Ssam	RESTOREpwfl(*0f)			# restore state
1777479596bSsam_doadump:
1787479596bSsam	.word 0
1790b8444b9Ssam0:	mtpr	$HIGH,$IPL
1800b8444b9Ssam#define	_rsstkmap _Sysmap+12	# powerfail storage, scb, rsstk, int stack
1817479596bSsam	tstl	dumpflag			# dump only once!
1827479596bSsam	bneq	1f
183844a1895Skarels	andl2	$~PG_PROT,_rsstkmap
184844a1895Skarels	orl2	$PG_KW,_rsstkmap		# Make dump stack r/w
1857479596bSsam	mtpr	$0,$TBIA
186844a1895Skarels	movl	$1,dumpflag
1877479596bSsam	movab	dumpflag,sp
1887479596bSsam	callf	$4,_dumpsys
1897479596bSsam1:
1907479596bSsam	halt
1917479596bSsam
1927479596bSsam/*
1937479596bSsam * Interrupt vector routines
1947479596bSsam */
1957479596bSsam	.globl	_waittime
1967479596bSsam#define	SCBVEC(name) \
1977479596bSsam	.align 2; \
1987479596bSsam	.globl _X/**/name; \
1997479596bSsam_X/**/name
2000b8444b9Ssam#define	PANIC(msg) \
2010b8444b9Ssam	clrl _waittime; pushab 1f; callf $8,_panic; 1: .asciz msg
2020b8444b9Ssam#define	PRINTF(n,msg) \
2030b8444b9Ssam	pushab 1f; callf $(n+2)*4,_printf; MSG(msg)
2047479596bSsam#define	MSG(msg) .data; 1: .asciz msg; .text
2050b8444b9Ssam/*
2064d144ff4Skarels * r0-r5 are saved across all faults and interrupts.
207477ef2c3Ssam * Routines below and those hidden in vbglue.s (device
2080b8444b9Ssam * interrupts) invoke the PUSHR/POPR macros to execute
2090b8444b9Ssam * this.  Also, certain stack frame offset calculations
2104d144ff4Skarels * use this, using the REGSPC definition (and FPSPC defined below).
2110b8444b9Ssam */
2124d144ff4Skarels#define	REGSPC	6*4
2134d144ff4Skarels#define	PUSHR	movab -REGSPC(sp),sp; storer $0x3f,(sp)
2144d144ff4Skarels#define	POPR	loadr $0x3f,(sp); movab REGSPC(sp),sp
2157479596bSsam
2160b8444b9Ssam/*
2170b8444b9Ssam * Floating point state is saved across faults and
2180b8444b9Ssam * interrupts.  The state occupies 4 longwords on
2190b8444b9Ssam * the stack:
2200b8444b9Ssam *	precision indicator (single = 0/double = 1)
2210b8444b9Ssam *	double representation of accumulator
2220b8444b9Ssam *	save accumulator status flag (pcb_savacc)
2230b8444b9Ssam */
2240b8444b9Ssam#define	FPSPC	(4*4)
2257479596bSsam
2260b8444b9Ssam#define SAVE_FPSTAT(_delta) \
2270b8444b9Ssam	bitl	$PSL_DBL,_delta(sp); \
2287479596bSsam	beql	1f; \
2297479596bSsam	pushl	$1; \
2307479596bSsam	pushd; \
2317479596bSsam	jmp	2f; \
2327479596bSsam1:	pushl	$0; \
2337479596bSsam	pushl	$0; \
2347479596bSsam	stf	-(sp); \
2357479596bSsam2:	tstl	_u+PCB_SAVACC; \
2367479596bSsam	bneq	3f; \
2377479596bSsam	moval	0(sp),_u+PCB_SAVACC; \
2387479596bSsam	orl2	$2,8(sp);\
2397479596bSsam3:	pushl	$0;
2407479596bSsam
2410b8444b9Ssam#define REST_FPSTAT \
2420b8444b9Ssam	tstl	(sp)+; \
2437479596bSsam	bitl	$2,8(sp);\
2447479596bSsam	beql	1f;\
2457479596bSsam	movl	$0,_u+PCB_SAVACC; \
2467479596bSsam1:	bitl	$1,8(sp); \
2477479596bSsam	beql	2f; \
2487479596bSsam	ldd	(sp); \
2497479596bSsam	jmp	3f; \
2507479596bSsam2:	ldf	(sp); \
2517479596bSsam3:	moval	12(sp),sp;
2527479596bSsam
2530b8444b9Ssam#define REST_ACC \
2540b8444b9Ssam	tstl	_u+PCB_SAVACC; \
2557479596bSsam	beql	2f; \
2567479596bSsam	movl	_u+PCB_SAVACC,r1; \
2577479596bSsam	andl3	$(EXPMASK|SIGNBIT),(r1),-(sp); \
2587479596bSsam	cmpl	$0x80000000,(sp)+; \
2597479596bSsam	bneq	3f; \
2607479596bSsam	clrl	(r1); \
2617479596bSsam3:	bitl	$1,8(r1); \
2627479596bSsam	beql	1f; \
2637479596bSsam	ldd	(r1); \
2647479596bSsam	jmp	2f; \
2657479596bSsam1:	ldf	(r1); \
2667479596bSsam2:	;
2677479596bSsam
2680b8444b9Ssam	.data
2690b8444b9Ssamnofault: .space	4			# bus error non-local goto label
2707479596bSsam
2710b8444b9Ssam	.text
2727479596bSsamSCBVEC(buserr):
2737479596bSsam	CHECK_SFE(12)
2740b8444b9Ssam	SAVE_FPSTAT(12)
2756ed0f239Ssam	incl	_intrcnt+I_BUSERR	# keep stats...
2760b8444b9Ssam	pushl	r0			# must save
2770b8444b9Ssam	andl3	24(sp),$ERRCD,r0	# grab pushed MER value
2780b8444b9Ssam	cmpl	r0,$APE			# address parity error?
2797479596bSsam	jneq	1f
2800b8444b9Ssam	halt
2810b8444b9Ssam1:	cmpl	r0,$VBE			# versabus error?
2820b8444b9Ssam	jneq	2f
2830b8444b9Ssam	halt
2840b8444b9Ssam2:
2850b8444b9Ssam	movl	(sp)+,r0		# restore r0 and...
2860b8444b9Ssam	bitl	$PSL_CURMOD,4*4+3*4(sp)	# check if happened in user mode?
2870b8444b9Ssam	jeql	3f			# yes, then shift stack up for trap...
2880b8444b9Ssam	movl	12(sp),16(sp)		# sorry, no space for which-buss...
2890b8444b9Ssam	movl	8(sp),12(sp)
2900b8444b9Ssam	movl	4(sp),8(sp)
2910b8444b9Ssam	movl	0(sp),4(sp)
2920b8444b9Ssam	movl	$T_BUSERR,0(sp)		# push trap type code and...
2930b8444b9Ssam	jbr	alltraps		# ...merge with all other traps
2940b8444b9Ssam3:					# kernel mode, check to see if...
2950b8444b9Ssam	tstl	nofault			# ...doing peek/poke?
2960b8444b9Ssam	jeql	4f			# nofault set? if so, jump to it...
2970b8444b9Ssam	movl	nofault,4*4+2*4(sp)	# ...setup for non-local goto
2980b8444b9Ssam	clrl	nofault
2990b8444b9Ssam	jbr	5f
3000b8444b9Ssam4:
3010b8444b9Ssam	PUSHR
3024d144ff4Skarels	pushab	4*4+REGSPC(sp)		# address of bus error parameters
3037479596bSsam	callf	$8,_buserror
3047479596bSsam	POPR
3050b8444b9Ssam5:
3060b8444b9Ssam	REST_FPSTAT
3070b8444b9Ssam	movab	8(sp),sp		# remove bus error parameters
3087479596bSsam	rei
3097479596bSsam
3107479596bSsamSCBVEC(powfail):			# We should be on interrupt stack now.
3110b8444b9Ssam	SAVEpwfl()			# save machine state
312477ef2c3Ssam	moval	_Xdoadump-SYSTEM,_scb+SCB_DOADUMP
3137479596bSsam	halt
3147479596bSsam
3157479596bSsamSCBVEC(stray):
3169dab7c56Ssam	incl	_cnt+V_INTR		# add to statistics
3177479596bSsam	rei
3187479596bSsam
319d357015aSbostic#include "net/netisr.h"
3207479596bSsam	.globl	_netisr
3217479596bSsamSCBVEC(netintr):
3227479596bSsam	CHECK_SFE(4)
323477ef2c3Ssam	SAVE_FPSTAT(4); PUSHR
324477ef2c3Ssam#include "imp.h"
325477ef2c3Ssam#if NIMP > 0
326477ef2c3Ssam	bbc	$NETISR_IMP,_netisr,1f;
327477ef2c3Ssam	andl2	$~(1<<NETISR_IMP),_netisr
328477ef2c3Ssam	callf	$4,_impintr;
3297479596bSsam1:
330477ef2c3Ssam#endif
3317479596bSsam#ifdef INET
3323651b6b8Ssklower	bbc	$NETISR_ARP,_netisr,1f
3333651b6b8Ssklower	andl2	$~(1<<NETISR_ARP),_netisr
3343651b6b8Ssklower	callf	$4,_arpintr
3353651b6b8Ssklower1:
3367479596bSsam	bbc	$NETISR_IP,_netisr,1f
3370b8444b9Ssam	andl2	$~(1<<NETISR_IP),_netisr
3387479596bSsam	callf	$4,_ipintr
3397479596bSsam1:
3407479596bSsam#endif
3417479596bSsam#ifdef NS
3427479596bSsam	bbc	$NETISR_NS,_netisr,1f
3430b8444b9Ssam	andl2	$~(1<<NETISR_NS),_netisr
3447479596bSsam	callf	$4,_nsintr
3457479596bSsam1:
3467479596bSsam#endif
347fb5e3f58Skarels#ifdef ISO
348fb5e3f58Skarels	bbc	$NETISR_ISO,_netisr,1f
349fb5e3f58Skarels	andl2	$~(1<<NETISR_ISO),_netisr
350fb5e3f58Skarels	callf	$4,_clnlintr
351477ef2c3Ssam1:
352fb5e3f58Skarels#endif
353477ef2c3Ssam	incl	_cnt+V_SOFT
354477ef2c3Ssam	POPR; REST_FPSTAT
3557479596bSsam	rei
3567479596bSsam
3577479596bSsamSCBVEC(cnrint):
3587479596bSsam	CHECK_SFE(4)
3597479596bSsam	SAVE_FPSTAT(4); PUSHR;
3606ed0f239Ssam	pushl $CPCONS; callf $8,_cnrint;
3616ed0f239Ssam	incl	_intrcnt+I_CNR
3626ed0f239Ssam	incl	_cnt+V_INTR
3630b8444b9Ssam	POPR; REST_FPSTAT;
3640b8444b9Ssam	rei
3657479596bSsamSCBVEC(cnxint):
3667479596bSsam	CHECK_SFE(4)
3677479596bSsam	SAVE_FPSTAT(4); PUSHR;
3686ed0f239Ssam	pushl $CPCONS; callf $8,_cnxint;
3696ed0f239Ssam	incl	_intrcnt+I_CNX
3706ed0f239Ssam	incl	_cnt+V_INTR
3710b8444b9Ssam	POPR; REST_FPSTAT;
3720b8444b9Ssam	rei
3737479596bSsamSCBVEC(rmtrint):
3747479596bSsam	CHECK_SFE(4)
3757479596bSsam	SAVE_FPSTAT(4); PUSHR;
3766ed0f239Ssam	pushl $CPREMOT; callf $8,_cnrint;
3776ed0f239Ssam	incl	_intrcnt+I_RMTR
3786ed0f239Ssam	incl	_cnt+V_INTR
3790b8444b9Ssam	POPR; REST_FPSTAT;
3800b8444b9Ssam	rei
3817479596bSsamSCBVEC(rmtxint):
3827479596bSsam	CHECK_SFE(4)
3837479596bSsam	SAVE_FPSTAT(4); PUSHR;
3846ed0f239Ssam	pushl $CPREMOT; callf $8,_cnxint;
3856ed0f239Ssam	incl	_intrcnt+I_RMTX
3866ed0f239Ssam	incl	_cnt+V_INTR
3870b8444b9Ssam	POPR; REST_FPSTAT;
3880b8444b9Ssam	rei
3897479596bSsam
3900b8444b9Ssam#define PUSHPCPSL	pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp);
3917479596bSsam
3927479596bSsamSCBVEC(hardclock):
3930b8444b9Ssam	tstl	_clk_enable
3940b8444b9Ssam	bneq	1f
3950b8444b9Ssam	rei
3960b8444b9Ssam1:
3977479596bSsam	CHECK_SFE(4)
3980b8444b9Ssam	SAVE_FPSTAT(4); PUSHR
3997479596bSsam	PUSHPCPSL			# push pc and psl
4007479596bSsam	callf	$12,_hardclock		# hardclock(pc,psl)
4016ed0f239Ssam	incl	_intrcnt+I_CLOCK
4027479596bSsam	incl	_cnt+V_INTR		## temp so not to break vmstat -= HZ
4030b8444b9Ssam	POPR; REST_FPSTAT
4047479596bSsam	rei
4057479596bSsamSCBVEC(softclock):
4067479596bSsam	CHECK_SFE(4)
4070b8444b9Ssam	SAVE_FPSTAT(4); PUSHR;
4087479596bSsam	PUSHPCPSL				# push pc and psl
4097479596bSsam	callf	$12,_softclock			# softclock(pc,psl)
4106ed0f239Ssam	incl	_cnt+V_SOFT
4110b8444b9Ssam	POPR; REST_FPSTAT
4127479596bSsam	rei
4137479596bSsam
4147479596bSsam/*
415477ef2c3Ssam * Stray VERSAbus interrupt catch routines
416477ef2c3Ssam */
417477ef2c3Ssam	.data
418477ef2c3Ssam#define	PJ	.align 2; callf $4,_Xvstray
419477ef2c3Ssam	.globl	_catcher
420477ef2c3Ssam_catcher:
421477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
422477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
423477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
424477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
425477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
426477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
427477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
428477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
429477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
430477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
431477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
432477ef2c3Ssam	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
433477ef2c3Ssam
434477ef2c3Ssam	.align	2
435477ef2c3Ssam	.globl	_cold
436477ef2c3Ssam_cold:	.long	0x3
437477ef2c3Ssam
438477ef2c3Ssam	.text
439477ef2c3SsamSCBVEC(vstray):
440477ef2c3Ssam	.word	0
441477ef2c3Ssam	bbc	$0,_cold,2f		# system running?
442477ef2c3Ssam	bbc	$1,_cold,1f		# doing autoconfig?
443477ef2c3Ssam	jbr	3f			# random interrupt, ignore
444477ef2c3Ssam1:
445477ef2c3Ssam	mfpr	$IPL,r12		# ...setup br and cvec
446477ef2c3Ssam	subl3	$_catcher+7,-8(fp),r11; shar $3,r11,r11
447477ef2c3Ssam	addl2	$SCB_DEVBASE,r11
448477ef2c3Ssam	jbr	3f
449477ef2c3Ssam2:
450477ef2c3Ssam	PUSHR
451477ef2c3Ssam	subl3	$_catcher+7,-8(fp),r0; shar $3,r0,r0
452477ef2c3Ssam	addl3	$SCB_DEVBASE,r0,-(sp);
453477ef2c3Ssam	mfpr	$IPL,-(sp)
454477ef2c3Ssam	PRINTF(2, "stray intr ipl %x vec %x\n")
455477ef2c3Ssam	POPR
456477ef2c3Ssam3:	moval	0f,-8(fp); ret		# pop callf frame...
457477ef2c3Ssam0:	rei				# ...and return
458477ef2c3Ssam
459477ef2c3Ssam/*
4607479596bSsam * Trap and fault vector routines
4617479596bSsam */
4627479596bSsam#define	TRAP(a)	pushl $T_/**/a; jbr alltraps
4637479596bSsam
4647479596bSsam/*
4657479596bSsam * Ast delivery (profiling and/or reschedule)
4667479596bSsam */
4677479596bSsam
4687479596bSsamSCBVEC(kspnotval):
4697479596bSsam	CHECK_SFE(4)
4707479596bSsam	pushl $0;
4717479596bSsam	SAVE_FPSTAT(8)
4727479596bSsam	TRAP(KSPNOTVAL)
4737479596bSsamSCBVEC(privinflt):
4747479596bSsam	CHECK_SFE(4)
4757479596bSsam	pushl $0;
4767479596bSsam	SAVE_FPSTAT(8)
4777479596bSsam	TRAP(PRIVINFLT)
4787479596bSsamSCBVEC(resopflt):
4797479596bSsam	CHECK_SFE(4)
4807479596bSsam	pushl $0;
4817479596bSsam	SAVE_FPSTAT(8)
4827479596bSsam	TRAP(RESOPFLT)
4837479596bSsamSCBVEC(resadflt):
4847479596bSsam	CHECK_SFE(4)
4857479596bSsam	pushl $0;
4867479596bSsam	SAVE_FPSTAT(8)
4877479596bSsam	TRAP(RESADFLT)
4887479596bSsamSCBVEC(bptflt):
4897479596bSsam	CHECK_SFE(4)
4907479596bSsam	pushl $0;
4917479596bSsam	SAVE_FPSTAT(8)
4927479596bSsam	TRAP(BPTFLT)
493e281991cSsamSCBVEC(kdbintr):
494e281991cSsam	CHECK_SFE(4);
495e281991cSsam	pushl $0;
496e281991cSsam	SAVE_FPSTAT(8);
497e281991cSsam	TRAP(KDBTRAP);
4987479596bSsamSCBVEC(tracep):
4997479596bSsam	CHECK_SFE(4)
5007479596bSsam	pushl $0;
5017479596bSsam	SAVE_FPSTAT(8)
5027479596bSsam	TRAP(TRCTRAP)
5037479596bSsamSCBVEC(alignflt):
50463a4e097Ssam#ifdef ALIGN
5059dab7c56Ssam	bitl	$PSL_CURMOD,4(sp)
5069dab7c56Ssam	jeql	align_excp		# Can't emulate for kernel mode !
5079dab7c56Ssam	jbr	non_aligned		# Only emulated for user mode.
5089dab7c56Ssamalign_excp:
5099dab7c56Ssam#else
5107479596bSsam	CHECK_SFE(4)
5119dab7c56Ssam#endif
5127479596bSsam	pushl $0;
5137479596bSsam	SAVE_FPSTAT(8)
5147479596bSsam	TRAP(ALIGNFLT)
5157479596bSsamSCBVEC(arithtrap):
5167479596bSsam	CHECK_SFE(8)
5177479596bSsam	SAVE_FPSTAT(8)
5187479596bSsam	TRAP(ARITHTRAP)
5197479596bSsam
5207479596bSsamSCBVEC(protflt):
5217479596bSsam	CHECK_SFE(12)
5227479596bSsam	bitl	$1,(sp)+
5237479596bSsam	jneq	segflt
5247479596bSsam	SAVE_FPSTAT(8)
5257479596bSsam	TRAP(PROTFLT)
5267479596bSsamsegflt:
5277479596bSsam	SAVE_FPSTAT(8)
5287479596bSsam	TRAP(SEGFLT)
5297479596bSsam
5300b8444b9SsamSCBVEC(fpm):			# Floating Point Emulation
53163a4e097Ssam#ifdef FPE
5327479596bSsam	CHECK_SFE(16)
5337479596bSsam	SAVE_FPSTAT(16)
5349dab7c56Ssam	incl	_cnt+V_FPE	# count emulation traps
5357479596bSsam	callf	$4,_fpemulate
5367479596bSsam	REST_FPSTAT
53763a4e097Ssam#endif
5387479596bSsam	moval	8(sp),sp	# Pop operand
5397479596bSsam	tstl	(sp)		# Stack= PSL, PC, return_code
5407479596bSsam	jneq	_Xarithtrap	# If not OK, emulate F.P. exception
5417479596bSsam	movab	4(sp),sp	# Else remove return_code and
5427479596bSsam	rei
5437479596bSsam
5447479596bSsamSCBVEC(sfexcep):
5457479596bSsam	CHECK_SFE(4)
5467479596bSsam	pushl $0
5477479596bSsam	SAVE_FPSTAT(8)
5487479596bSsam	TRAP(ASTFLT)
5497479596bSsam
5507479596bSsamSCBVEC(transflt):
5517479596bSsam	CHECK_SFE(12)
55220b06c77Skarels	bitl	$2,(sp)+
5537479596bSsam	bneq	tableflt
5547479596bSsampageflt:
5557479596bSsam	SAVE_FPSTAT(8)
5567479596bSsam	TRAP(PAGEFLT)
5577479596bSsamtableflt:
5587479596bSsam	SAVE_FPSTAT(8)
5597479596bSsam	TRAP(TABLEFLT)
5607479596bSsam
5617479596bSsam#define REST_STACK	movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
5627479596bSsam
5637479596bSsamalltraps:
5647479596bSsam	mfpr	$USP,-(sp);
5650b8444b9Ssam	callf	$4,_trap;
5660b8444b9Ssam	mtpr	(sp)+,$USP
5677479596bSsam	incl	_cnt+V_TRAP
5680b8444b9Ssam	REST_STACK			# pop type, code, and fp stuff
5697479596bSsam	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
5707479596bSsam	rei
5717479596bSsam
5727479596bSsamSCBVEC(syscall):
5737479596bSsam	CHECK_SFE(8)
5747479596bSsam	SAVE_FPSTAT(8)
5757479596bSsam	pushl	$T_SYSCALL
5760b8444b9Ssam	mfpr	$USP,-(sp);
5770b8444b9Ssam	callf	$4,_syscall;
5780b8444b9Ssam	mtpr	(sp)+,$USP
5797479596bSsam	incl	_cnt+V_SYSCALL
5800b8444b9Ssam	REST_STACK			# pop type, code, and fp stuff
5817479596bSsam	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
5827479596bSsam	rei
5837479596bSsam
5847479596bSsam/*
58557e96b6cSsam * System page table.
58657e96b6cSsam *
587477ef2c3Ssam * Mbmap and Usrptmap are enlarged by CLSIZE entries
588477ef2c3Ssam * as they are managed by resource maps starting with index 1 or CLSIZE.
5897479596bSsam */
5907479596bSsam#define	vaddr(x)	((((x)-_Sysmap)/4)*NBPG+SYSTEM)
5917479596bSsam#define	SYSMAP(mname, vname, npte)			\
5927479596bSsam_/**/mname:	.globl	_/**/mname;		\
593477ef2c3Ssam	.space	(npte)*4;			\
5947479596bSsam	.globl	_/**/vname;			\
5957479596bSsam	.set	_/**/vname,vaddr(_/**/mname)
5965bffa242Skarels#define	ADDMAP(npte)	.space	(npte)*4
5977479596bSsam
5987479596bSsam	.data
5997479596bSsam	.align	2
6007479596bSsam	SYSMAP(Sysmap	,Sysbase	,SYSPTSIZE	)
6017479596bSsam	SYSMAP(Forkmap	,forkutl	,UPAGES		)
6027479596bSsam	SYSMAP(Xswapmap	,xswaputl	,UPAGES		)
6037479596bSsam	SYSMAP(Xswap2map,xswap2utl	,UPAGES		)
6047479596bSsam	SYSMAP(Swapmap	,swaputl	,UPAGES		)
6057479596bSsam	SYSMAP(Pushmap	,pushutl	,UPAGES		)
6067479596bSsam	SYSMAP(Vfmap	,vfutl		,UPAGES		)
6077479596bSsam	SYSMAP(CMAP1	,CADDR1		,1		)
6087479596bSsam	SYSMAP(CMAP2	,CADDR2		,1		)
6097479596bSsam	SYSMAP(mmap	,vmmap		,1		)
610477ef2c3Ssam	SYSMAP(alignmap	,alignutl	,1		)	/* XXX */
6117479596bSsam	SYSMAP(msgbufmap,msgbuf		,MSGBUFPTECNT	)
6129ea5c536Sbostic	SYSMAP(Mbmap	,mbutl		,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE )
61382e348a9Smckusick#ifdef MFS
614d357015aSbostic#include "ufs/mfsiom.h"
6159dcee661Smckusick	/*
61682e348a9Smckusick	 * Used by the mfs_doio() routine for physical I/O
6179dcee661Smckusick	 */
61882e348a9Smckusick	SYSMAP(Mfsiomap	,mfsiobuf	,MFS_MAPREG )
61982e348a9Smckusick#endif /* MFS */
62082e348a9Smckusick#ifdef NFS
621d357015aSbostic#include "nfs/nfsiom.h"
62282e348a9Smckusick	/*
62382e348a9Smckusick	 * Used by the nfs_doio() routine for physical I/O
62482e348a9Smckusick	 */
62582e348a9Smckusick	SYSMAP(Nfsiomap	,nfsiobuf	,NFS_MAPREG )
6269dcee661Smckusick#endif /* NFS */
627e7123664Smckusick	/*
6288fd09904Smckusick	 * This is the map used by the kernel memory allocator.
6298fd09904Smckusick	 * It is expanded as necessary by the special features
6308fd09904Smckusick	 * that use it.
6318fd09904Smckusick	 */
6322ee96521Smckusick	SYSMAP(kmempt	,kmembase	,NKMEMCLUSTERS*CLSIZE	)
6332ee96521Smckusick#ifdef	SYSVSHM
6342ee96521Smckusick				ADDMAP(	SHMMAXPGS	)
6352ee96521Smckusick#endif
6368fd09904Smckusick#ifdef	GPROF
6378fd09904Smckusick				ADDMAP( 600*CLSIZE	)
6388fd09904Smckusick#endif
6398fd09904Smckusick	/*
640dbe30e8bSkarels	 * Enlarge kmempt as needed for bounce buffers allocated
641e7123664Smckusick	 * by tahoe controllers.
642e7123664Smckusick	 */
6439ea5c536Sbostic#include "hd.h"
6449ea5c536Sbostic#if NHD > 0
6459ea5c536Sbostic				ADDMAP(	NHDC*(MAXPHYS/NBPG+CLSIZE) )
6469ea5c536Sbostic#endif
647e7123664Smckusick#include "dk.h"
6489ea5c536Sbostic#if NDK > 0
6495bffa242Skarels				ADDMAP(	NVD*(MAXPHYS/NBPG+CLSIZE) )
6509ea5c536Sbostic#endif
651e7123664Smckusick#include "yc.h"
6529ea5c536Sbostic#if NYC > 0
6535bffa242Skarels				ADDMAP(	NCY*(MAXPHYS/NBPG+CLSIZE) )
6549ea5c536Sbostic#endif
655dbe30e8bSkarels#include "mp.h"
6565bffa242Skarels				ADDMAP(	NMP*14		)
657dbe30e8bSkarels	SYSMAP(ekmempt	,kmemlimit	,0		)
658dbe30e8bSkarels
659477ef2c3Ssam	SYSMAP(VMEMbeg	,vmembeg	,0		)
66057e96b6cSsam	SYSMAP(VMEMmap	,vmem		,VBIOSIZE 	)
661e7123664Smckusick	SYSMAP(VMEMmap1	,vmem1		,0		)
662e7123664Smckusick#include "ace.h"
663bbf21aa2Sbostic#if NACE > 0
6645bffa242Skarels				ADDMAP(	NACE*32	)
665bbf21aa2Sbostic#endif
666bbf21aa2Sbostic#if NHD > 0
667bbf21aa2Sbostic				ADDMAP( NHDC )
668bbf21aa2Sbostic#endif
669fb5e3f58Skarels#include "vx.h"
670fb5e3f58Skarels#if NVX > 0
671fb5e3f58Skarels				ADDMAP( NVX * 16384/NBPG )
672fb5e3f58Skarels#endif
673477ef2c3Ssam	SYSMAP(VMEMend	,vmemend	,0		)
674dbe30e8bSkarels
67520b06c77Skarels	SYSMAP(VBmap	,vbbase		,CLSIZE		)
6769ea5c536Sbostic#if NHD > 0
6779ea5c536Sbostic				ADDMAP(	NHDC*(MAXPHYS/NBPG+CLSIZE) )
6789ea5c536Sbostic#endif
6799ea5c536Sbostic#if NDK > 0
6805bffa242Skarels				ADDMAP(	NVD*(MAXPHYS/NBPG+CLSIZE) )
6819ea5c536Sbostic#endif
6829ea5c536Sbostic#if NYC > 0
6835bffa242Skarels				ADDMAP(	NCY*(MAXPHYS/NBPG+CLSIZE) )
6849ea5c536Sbostic#endif
6855bffa242Skarels				ADDMAP(	NMP*14		)
68657e96b6cSsam	SYSMAP(eVBmap	,vbend		,0		)
687dbe30e8bSkarels
688477ef2c3Ssam	SYSMAP(Usrptmap	,usrpt		,USRPTSIZE+CLSIZE )
6897479596bSsameSysmap:
6907479596bSsam	.globl	_Syssize
6917479596bSsam	.set	_Syssize,(eSysmap-_Sysmap)/4
6927479596bSsam
6937479596bSsam	.text
6947479596bSsam/*
6957479596bSsam * Initialization
6967479596bSsam *
6977479596bSsam * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
6987479596bSsam */
6997479596bSsam	.align	2
7007479596bSsam	.globl	start
7017479596bSsamstart:
7027479596bSsam	.word	0
7037479596bSsam/* set system control block base and system page table params */
7047479596bSsam	mtpr	$_scb-SYSTEM,$SCBB
7057479596bSsam	mtpr	$_Sysmap-SYSTEM,$SBR
7067479596bSsam	mtpr	$_Syssize,$SLR
7077479596bSsam/* double map the kernel into the virtual user addresses of phys mem */
7087479596bSsam	mtpr	$_Sysmap,$P0BR
7097479596bSsam	mtpr	$_Syssize,$P0LR
7100b8444b9Ssam	mtpr	$_Sysmap,$P1BR			# against Murphy
7117479596bSsam	mtpr	$_Syssize,$P1LR
7127479596bSsam/* set ISP */
7130b8444b9Ssam	movl	$_intstack-SYSTEM+NISP*NBPG,sp	# still physical
7147479596bSsam	mtpr	$_intstack+NISP*NBPG,$ISP
715fb5e3f58Skarels/* count up memory; _physmem contains limit */
7167479596bSsam	clrl	r7
717fb5e3f58Skarels	shll	$PGSHIFT,_physmem,r8
718fb5e3f58Skarels	decl	r8
7197479596bSsam1:	pushl	$1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
720fb5e3f58Skarels	ACBL(r8,$64*1024,r7,1b)
7217479596bSsam9:
7227479596bSsam/* clear memory from kernel bss and pages for proc 0 u. and page table */
723e281991cSsam	movab	_edata,r6; andl2 $~SYSTEM,r6
724e281991cSsam	movab	_end,r5; andl2 $~SYSTEM,r5
725189fe34eSkarels#ifdef KADB
726e281991cSsam	subl2	$4,r5
727e281991cSsam1:	clrl	(r6); ACBL(r5,$4,r6,1b)		# clear just bss
728e281991cSsam	addl2	$4,r5
729e281991cSsam	bbc	$6,r11,0f			# check RB_KDB
730e281991cSsam	andl3	$~SYSTEM,r9,r5			# skip symbol & string tables
731e281991cSsam	andl3	$~SYSTEM,r9,r6
732e281991cSsam#endif
733e281991cSsam0:	orl3	$SYSTEM,r5,r9			# convert to virtual address
734e281991cSsam	addl2	$NBPG-1,r9			# roundup to next page
7357479596bSsam	addl2	$(UPAGES*NBPG)+NBPG+NBPG,r5
7367479596bSsam1:	clrl	(r6); ACBL(r5,$4,r6,1b)
7370b8444b9Ssam/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */
7387479596bSsam	orw2	$0x01fff,_trap
7397479596bSsam	orw2	$0x01fff,_syscall
74063a4e097Ssam#ifdef FPE
7417479596bSsam	orw2	$0x01fff,_fpemulate
74263a4e097Ssam#endif
7430b8444b9Ssam	orw2	$0x01ffc,_panic			# for debugging (no r0|r1)
744477ef2c3Ssam	callf	$4,_fixctlrmask			# setup for autoconfig
7457479596bSsam/* initialize system page table: scb and int stack writeable */
7467479596bSsam	clrl	r2
7477479596bSsam	movab	eintstack,r1
7480b8444b9Ssam	andl2	$~SYSTEM,r1
7490b8444b9Ssam	shrl 	$PGSHIFT,r1,r1			# r1-page number of eintstack
750844a1895Skarels/* make 1st page processor storage read/only, 2nd read/write */
7517479596bSsam	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
752844a1895Skarels	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]; incl r2;
7530b8444b9Ssam/* other parts of the system are read/write for kernel */
7547479596bSsam1:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2];	# data:kernel write+phys=virtual
7557479596bSsam	aoblss r1,r2,1b
7567479596bSsam/* make rsstk read-only as red zone for interrupt stack */
7570b8444b9Ssam	andl2	$~PG_PROT,_rsstkmap
7580b8444b9Ssam	orl2	$PG_V|PG_KR,_rsstkmap
7597479596bSsam/* make kernel text space read-only */
7607479596bSsam	movab	_etext+NBPG-1,r1
7610b8444b9Ssam	andl2	$~SYSTEM,r1
7627479596bSsam	shrl 	$PGSHIFT,r1,r1
7637479596bSsam1:	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]
7647479596bSsam	aoblss r1,r2,1b
7657479596bSsam/* make kernel data, bss, read-write */
766e281991cSsam	andl3	$~SYSTEM,r9,r1
7677479596bSsam	shrl 	$PGSHIFT,r1,r1
7687479596bSsam1:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]
7697479596bSsam	aoblss r1,r2,1b
7700b8444b9Ssam/* go to mapped mode, have to change both pc and sp to system addresses */
7717479596bSsam	mtpr	$1,$TBIA
7720b8444b9Ssam	mtpr	$1,$PADC			# needed by HW parity&ECC logic
7730b8444b9Ssam	mtpr	$1,$PACC			# just in case
7747479596bSsam	mtpr 	$1,$MME
7757479596bSsam	movab	SYSTEM(sp),sp
7767479596bSsam	jmp 	*$0f
7777479596bSsam0:
7787479596bSsam/* disable any interrupts */
7797479596bSsam	movl	$0,_intenable
7807479596bSsam/* init mem sizes */
781fb5e3f58Skarels	shrl	$PGSHIFT,r7,_physmem
7820b8444b9Ssam/* setup context for proc[0] == scheduler */
783e281991cSsam	andl3	$~SYSTEM,r9,r6			# convert to physical
7840b8444b9Ssam	andl2	$~(NBPG-1),r6			# make page boundary
7857479596bSsam/* setup page table for proc[0] */
7867479596bSsam	shrl	$PGSHIFT,r6,r3			# r3 = btoc(r6)
7877479596bSsam	orl3	$PG_V|PG_KW,r3,_Usrptmap	# init first upt entry
7887479596bSsam	incl	r3				# r3 - next page
7897479596bSsam	movab	_usrpt,r0			# r0 - first user page
7907479596bSsam	mtpr	r0,$TBIS
7917479596bSsam/* init p0br, p0lr */
7920b8444b9Ssam	mtpr	r0,$P0BR			# no p0 for proc[0]
7937479596bSsam	mtpr	$0,$P0LR
7940b8444b9Ssam	mtpr	r0,$P1BR			# no p1 either
7957479596bSsam	mtpr	$0,$P1LR
7967479596bSsam/* init p2br, p2lr */
7977479596bSsam	movab	NBPG(r0),r0
7987479596bSsam	movl	$PPAGES-UPAGES,r1
7997479596bSsam	mtpr	r1,$P2LR
8007479596bSsam	moval	-4*PPAGES(r0),r2
8017479596bSsam	mtpr	r2,$P2BR
8027479596bSsam/* setup mapping for UPAGES of _u */
8030b8444b9Ssam	clrl	r2
8047479596bSsam	movl 	$SYSTEM,r1
8057479596bSsam	addl2 	$UPAGES,r3
8067479596bSsam	jbr 2f
8077479596bSsam1:	decl	r3
8080b8444b9Ssam	moval	-NBPG(r1),r1	# r1 = virtual add of next (downward) _u page
8097479596bSsam	subl2	$4,r0		# r0 = pte address
8107479596bSsam	orl3	$PG_V|PG_URKW,r3,(r0)
8117479596bSsam	mtpr	r1,$TBIS
8127479596bSsam2:	aobleq	$UPAGES,r2,1b
8137479596bSsam/* initialize (slightly) the pcb */
8147479596bSsam	movab	UPAGES*NBPG(r1),PCB_KSP(r1)	# KSP starts at end of _u
8157479596bSsam	movl	r1,PCB_USP(r1)			# USP starts just below _u
8167479596bSsam	mfpr	$P0BR,PCB_P0BR(r1)
8177479596bSsam	mfpr	$P0LR,PCB_P0LR(r1)
8187479596bSsam	mfpr	$P1BR,PCB_P1BR(r1)
8197479596bSsam	mfpr	$P1LR,PCB_P1LR(r1)
8207479596bSsam	mfpr	$P2BR,PCB_P2BR(r1)
8217479596bSsam	mfpr	$P2LR,PCB_P2LR(r1)
8227479596bSsam	movl	$CLSIZE,PCB_SZPT(r1)		# init u.u_pcb.pcb_szpt
823e281991cSsam	movl	r9,PCB_R9(r1)			# r9 obtained from boot
824e281991cSsam	movl	r10,PCB_R10(r1)			# r10 obtained from boot
8257479596bSsam	movl	r11,PCB_R11(r1)			# r11 obtained from CP on boot
8267479596bSsam	movab	1f,PCB_PC(r1)			# initial pc
8277479596bSsam	clrl	PCB_PSL(r1)			# kernel mode, ipl=0
8287479596bSsam	shll	$PGSHIFT,r3,r3
8290b8444b9Ssam	mtpr	r3,$PCBB			# first pcbb (physical)
8300b8444b9Ssam/* go to kernel mode */
8317479596bSsam	ldpctx
8320b8444b9Ssam	rei					# Actually next instruction:
8337479596bSsam/* put signal trampoline code in u. area */
8340b8444b9Ssam1:	movab	sigcode,r0
8350b8444b9Ssam	movab	_u+PCB_SIGC,r1
8360b8444b9Ssam	movl	$19,r2
8370b8444b9Ssam	movblk
838bbb01fa4Ssam/* save boot device in global _bootdev */
839bbb01fa4Ssam	movl	r10,_bootdev
8407479596bSsam/* save reboot flags in global _boothowto */
8417479596bSsam	movl	r11,_boothowto
8423274904bSbostic#ifdef KADB
843e281991cSsam/* save end of symbol & string table in global _bootesym */
844e281991cSsam	subl3	$NBPG-1,r9,_bootesym
8453274904bSbostic#endif
8467479596bSsam/* calculate firstaddr, and call main() */
847e281991cSsam	andl3	$~SYSTEM,r9,r0
8487479596bSsam	shrl	$PGSHIFT,r0,-(sp)
8490b8444b9Ssam	addl2	$UPAGES+1,(sp)			# first physical unused page
8507479596bSsam	callf 	$8,_main
8517479596bSsam/* proc[1] == /etc/init now running here in kernel mode; run icode */
8527479596bSsam	pushl	$PSL_CURMOD			# User mode PSL
8537479596bSsam	pushl $0				# PC = 0 (virtual now)
8547479596bSsam	rei
8557479596bSsam
8560b8444b9Ssam/*
8570b8444b9Ssam * Mask for saving/restoring registers on entry to
8580b8444b9Ssam * a user signal handler.  Space for the registers
8590b8444b9Ssam * is reserved in sendsig, so beware if you want
8600b8444b9Ssam * to change the mask.
8610b8444b9Ssam */
8620b8444b9Ssam#define	SIGREGS	(R0|R1|R2|R3|R4|R5)
8637479596bSsam	.align	2
8640b8444b9Ssam	.globl	sigcode
8650b8444b9Ssamsigcode:
8660b8444b9Ssam	storer	$SIGREGS,16(sp)	# save volatile registers
8670b8444b9Ssam	calls	$4*3+4,*12(sp)	# params pushed by sendsig for handler
8680b8444b9Ssam	loadr	$SIGREGS,4(sp)	# restore volatile registers
8690b8444b9Ssam	movab	24(sp),fp	# use parameter list set up in sendsig
8700b8444b9Ssam	kcall	$SYS_sigreturn	# cleanup mask and onsigstack
8710b8444b9Ssam	halt			# sigreturn does not return!
8720b8444b9Ssam
8730b8444b9Ssam	.globl	_icode
8740b8444b9Ssam	.globl	_initflags
8750b8444b9Ssam	.globl	_szicode
876f5e105aeSmckusick	.data
8770b8444b9Ssam/*
8780b8444b9Ssam * Icode is copied out to process 1 to exec /etc/init.
8790b8444b9Ssam * If the exec fails, process 1 exits.
8800b8444b9Ssam */
8810b8444b9Ssam	.align	2
8820b8444b9Ssam_icode:
88319e071f5Sbostic	/* try /sbin/init */
884250e3e7bSkarels	pushl	$0
88519e071f5Sbostic	pushab	b`argv1-l0(pc)
88619e071f5Sbosticl0:	pushab	b`init1-l1(pc)
8870b8444b9Ssaml1:	pushl	$2
8880b8444b9Ssam	movab	(sp),fp
889250e3e7bSkarels	kcall	$SYS_execve
89019e071f5Sbostic	/* try /etc/init */
891250e3e7bSkarels	pushl	$0
89219e071f5Sbostic	pushab	b`argv2-l2(pc)
89319e071f5Sbosticl2:	pushab	b`init2-l3(pc)
89419e071f5Sbosticl3:	pushl	$2
89519e071f5Sbostic	movab	(sp),fp
896250e3e7bSkarels	kcall	$SYS_execve
89719e071f5Sbostic	/* give up */
898e034e083Skarels	pushl	r0
89919e071f5Sbostic	pushl	$1
90019e071f5Sbostic	movab	(sp),fp
9010b8444b9Ssam	kcall	$SYS_exit
9020b8444b9Ssam
90319e071f5Sbosticinit1:	.asciz	"/sbin/init"
90419e071f5Sbosticinit2:	.asciz	"/etc/init"
9050b8444b9Ssam	.align	2
9060b8444b9Ssam_initflags:
9070b8444b9Ssam	.long	0
90819e071f5Sbosticargv1:	.long	init1+6-_icode
90919e071f5Sbostic	.long	_initflags-_icode
91019e071f5Sbostic	.long	0
91119e071f5Sbosticargv2:	.long	init2+5-_icode
9120b8444b9Ssam	.long	_initflags-_icode
9130b8444b9Ssam	.long	0
9140b8444b9Ssam_szicode:
9150b8444b9Ssam	.long	_szicode-_icode
916f5e105aeSmckusick	.text
9177479596bSsam
9187479596bSsam/*
9197479596bSsam * Primitives
9207479596bSsam */
9217479596bSsam
9227479596bSsam/*
9237479596bSsam * badaddr(addr, len)
9247479596bSsam *	see if access addr with a len type instruction causes a machine check
9257479596bSsam *	len is length of access (1=byte, 2=short, 4=long)
9267479596bSsam *	r0 = 0 means good(exists); r0 =1 means does not exist.
9277479596bSsam */
9280b8444b9SsamENTRY(badaddr, R3|R4)
9297479596bSsam	mfpr	$IPL,r1
9307479596bSsam	mtpr	$HIGH,$IPL
931477ef2c3Ssam	movl	_scb+SCB_BUSERR,r2
9327479596bSsam	movl	4(fp),r3
9337479596bSsam	movl	8(fp),r4
934477ef2c3Ssam	movab	9f,_scb+SCB_BUSERR
9357479596bSsam	bbc	$0,r4,1f; tstb	(r3)
9367479596bSsam1:	bbc	$1,r4,1f; tstw	(r3)
9377479596bSsam1:	bbc	$2,r4,1f; tstl	(r3)
9380b8444b9Ssam1:	clrl	r0
939477ef2c3Ssam2:	movl	r2,_scb+SCB_BUSERR
9407479596bSsam	mtpr	r1,$IPL
9417479596bSsam	ret
9427479596bSsam
943cff2b5daSbostic/*
944cff2b5daSbostic * wbadaddr(addr, len, value)
945cff2b5daSbostic *	see if write of value to addr with a len type instruction causes
946cff2b5daSbostic *	a machine check
947cff2b5daSbostic *	len is length of access (1=byte, 2=short, 4=long)
948cff2b5daSbostic *	r0 = 0 means good(exists); r0 =1 means does not exist.
949cff2b5daSbostic */
950cff2b5daSbosticENTRY(wbadaddr, R3|R4)
951cff2b5daSbostic	mfpr	$IPL,r1
952cff2b5daSbostic	mtpr	$HIGH,$IPL
953cff2b5daSbostic	movl	_scb+SCB_BUSERR,r2
954cff2b5daSbostic	movl	4(fp),r3
955cff2b5daSbostic	movl	8(fp),r4
956cff2b5daSbostic	movab	9f,_scb+SCB_BUSERR
957cff2b5daSbostic	bbc	$0,r4,1f; movb	15(fp), (r3)
958cff2b5daSbostic1:	bbc	$1,r4,1f; movw	14(fp), (r3)
959cff2b5daSbostic1:	bbc	$2,r4,1f; movl	12(fp), (r3)
960fb5e3f58Skarels1:	movl	$30000,r0		# delay for error interrupt
961fb5e3f58Skarels1:	decl	r0
962fb5e3f58Skarels	jneq	1b
963fb5e3f58Skarels2:	movl	r2,_scb+SCB_BUSERR	# made it w/o machine checks; r0 is 0
964cff2b5daSbostic	mtpr	r1,$IPL
965cff2b5daSbostic	ret
966cff2b5daSbostic
9677479596bSsam	.align	2
9680b8444b9Ssam9:				# catch buss error (if it comes)
9697479596bSsam	andl3	4(sp),$ERRCD,r0
9707479596bSsam	cmpl	r0,$APE
9717479596bSsam	jneq	1f
9720b8444b9Ssam	halt			# address parity error
9737479596bSsam1:	cmpl	r0,$VBE
9747479596bSsam	jneq	1f
9757479596bSsam	halt			# Versabus error
9767479596bSsam1:
9777479596bSsam	movl	$1,r0		# Anything else = bad address
9787479596bSsam	movab	8(sp),sp	# discard buss error trash
9797479596bSsam	movab	2b,(sp)		# new program counter on stack.
9807479596bSsam	rei
9817479596bSsam
9827479596bSsam/*
9837479596bSsam * badcyaddr(addr)
9847479596bSsam *	see if access tape master controller addr causes a bus error
9857479596bSsam *	r0 = 0: no error; r0 = 1: timeout error.
9867479596bSsam */
9870b8444b9SsamENTRY(badcyaddr, 0)
9887479596bSsam	mfpr	$IPL,r1
9897479596bSsam	mtpr	$HIGH,$IPL
9900b8444b9Ssam	clrl	r2
9910b8444b9Ssam	movab	2f,nofault
9927479596bSsam	movob	$-1, *4(fp)
9930b8444b9Ssam1:	aobleq	$1000, r2, 1b
9940b8444b9Ssam	clrl	nofault			# made it w/o bus error
9950b8444b9Ssam	clrl	r0
9960b8444b9Ssam	jbr	3f
9970b8444b9Ssam2:	movl	$1,r0
9980b8444b9Ssam3:	mtpr	r1,$IPL
9997479596bSsam	ret
10007479596bSsam
10010b8444b9Ssam/*
10020b8444b9Ssam * peek(addr)
10030b8444b9Ssam *	fetch word and catch any bus error
10040b8444b9Ssam */
10050b8444b9SsamENTRY(peek, 0)
10060b8444b9Ssam	mfpr	$IPL,r1
10070b8444b9Ssam	mtpr	$0x18,$IPL	# not reentrant
10080b8444b9Ssam	movl	4(fp),r2
10090b8444b9Ssam	movab	1f,nofault
10100b8444b9Ssam	movw	(r2),r0
10110b8444b9Ssam	clrl	nofault
10120b8444b9Ssam	andl2	$0xffff,r0
10130b8444b9Ssam	jbr	2f
10140b8444b9Ssam1:	movl	$-1,r0		# bus error
10150b8444b9Ssam2:	mtpr	r1,$IPL
10167479596bSsam	ret
10177479596bSsam
10180b8444b9Ssam/*
10190b8444b9Ssam * poke(addr, val)
10200b8444b9Ssam *	write word and catch any bus error
10210b8444b9Ssam */
10220b8444b9SsamENTRY(poke, R3)
10230b8444b9Ssam	mfpr	$IPL,r1
10240b8444b9Ssam	mtpr	$0x18,$IPL	# not reentrant
10250b8444b9Ssam	movl	4(fp),r2
10260b8444b9Ssam	movl	8(fp),r3
10270b8444b9Ssam	clrl	r0
10280b8444b9Ssam	movab	1f,nofault
10290b8444b9Ssam	movw	r3,(r2)
10300b8444b9Ssam	clrl	nofault
10310b8444b9Ssam	jbr	2f
10320b8444b9Ssam1:	movl	$-1,r0		# bus error
10330b8444b9Ssam2:	mtpr	r1,$IPL
10340b8444b9Ssam	ret
10350b8444b9Ssam
10360b8444b9Ssam/*
10370b8444b9Ssam * Copy a potentially overlapping block of memory.
10380b8444b9Ssam *
10390b8444b9Ssam * ovbcopy(src, dst, count)
10400b8444b9Ssam *	caddr_t src, dst; unsigned count;
10410b8444b9Ssam */
10420b8444b9SsamENTRY(ovbcopy, R3|R4)
10437479596bSsam	movl	4(fp),r0
10447479596bSsam	movl	8(fp),r1
10457479596bSsam	movl	12(fp),r2
10467479596bSsam	cmpl	r0,r1
10477479596bSsam	bgtru	1f			# normal forward case
10487479596bSsam	beql	2f			# equal, nothing to do
10497479596bSsam	addl2	r2,r0			# may be overlapping
10507479596bSsam	cmpl	r0,r1
10517479596bSsam	bgtru	3f
10527479596bSsam	subl2	r2,r0			# normal forward case
10537479596bSsam1:
10547479596bSsam	movblk
10557479596bSsam2:
10567479596bSsam	ret
10577479596bSsam3:
10587479596bSsam	addl2	r2,r1			# overlapping, must do backwards
10597479596bSsam	subl3	r0,r1,r3
10607479596bSsam	movl	r2,r4
10617479596bSsam	jbr	5f
10627479596bSsam4:
10637479596bSsam	subl2	r3,r0
10647479596bSsam	subl2	r3,r1
10657479596bSsam	movl	r3,r2
10667479596bSsam	movblk
10677479596bSsam	subl2	r3,r0
10687479596bSsam	subl2	r3,r1
10697479596bSsam	subl2	r3,r4
10707479596bSsam5:
10717479596bSsam	cmpl	r4,r3
10727479596bSsam	jgtr	4b
10737479596bSsam	movl	r4,r2
10747479596bSsam	subl2	r2,r0
10757479596bSsam	subl2	r2,r1
10767479596bSsam	movblk
10777479596bSsam	ret
10787479596bSsam
10797479596bSsam/*
10800b8444b9Ssam * Copy a null terminated string from the user address space into
10810b8444b9Ssam * the kernel address space.
10820b8444b9Ssam *
10830b8444b9Ssam * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
10847479596bSsam */
108547fd5358SmckusickENTRY(copyinstr, 0)
10860b8444b9Ssam	movl	12(fp),r5		# r5 = max length
108747fd5358Smckusick	jlss	5f
108847fd5358Smckusick	movl	8(fp),r4		# r4 = kernel address
10890b8444b9Ssam	movl	4(fp),r0		# r0 = user address
10900b8444b9Ssam	andl3	$(NBPG*CLSIZE-1),r0,r2	# r2 = bytes on first page
10910b8444b9Ssam	subl3	r2,$(NBPG*CLSIZE),r2
10927479596bSsam1:
10930b8444b9Ssam	cmpl	r5,r2			# r2 = min(bytes on page, length left);
10940b8444b9Ssam	jgeq	2f
10950b8444b9Ssam	movl	r5,r2
10960b8444b9Ssam2:
10970b8444b9Ssam	prober	$1,(r0),r2		# bytes accessible?
109847fd5358Smckusick	jeql	5f
10990b8444b9Ssam	subl2	r2,r5			# update bytes left count
110047fd5358Smckusick	movl	r2,r3			# r3 = saved count
110147fd5358Smckusick	movl	r0,r1
110247fd5358Smckusick	cmps3				# check for null
110347fd5358Smckusick	tstl	r2
11040b8444b9Ssam	jneq	3f
110547fd5358Smckusick	subl2	r3,r0			# back up r0
110647fd5358Smckusick	movl	r4,r1
110747fd5358Smckusick	movl	r3,r2
110847fd5358Smckusick	movblk				# copy in next piece
110947fd5358Smckusick	movl	r1,r4
11100b8444b9Ssam	movl	$(NBPG*CLSIZE),r2	# check next page
11110b8444b9Ssam	tstl	r5			# run out of space?
11120b8444b9Ssam	jneq	1b
111398cc6a9fSmckusick	movl	$ENAMETOOLONG,r0	# set error code and return
111447fd5358Smckusick	jbr	6f
11150b8444b9Ssam3:
11160b8444b9Ssam	tstl	16(fp)			# return length?
11170b8444b9Ssam	beql	4f
11180b8444b9Ssam	subl3	r5,12(fp),r5		# actual len = maxlen - unused pages
11190b8444b9Ssam	subl2	r2,r5			#	- unused on this page
11200b8444b9Ssam	addl3	$1,r5,*16(fp)		#	+ the null byte
11210b8444b9Ssam4:
112247fd5358Smckusick	movl	r4,r1
112347fd5358Smckusick	subl3	r2,r3,r2		# calc char cnt
112447fd5358Smckusick	subl2	r2,r0			# back up r0
112547fd5358Smckusick	incl	r2			# add on null byte
112647fd5358Smckusick	movblk				# copy last piece
11277479596bSsam	clrl	r0
11287479596bSsam	ret
112947fd5358Smckusick5:
11300b8444b9Ssam	movl	$EFAULT,r0
113147fd5358Smckusick6:
11320b8444b9Ssam	tstl	16(fp)
113347fd5358Smckusick	beql	7f
11340b8444b9Ssam	subl3	r5,12(fp),*16(fp)
113547fd5358Smckusick7:
11360b8444b9Ssam	ret
11377479596bSsam
11380b8444b9Ssam/*
11390b8444b9Ssam * Copy a null terminated string from the kernel
11400b8444b9Ssam * address space to the user address space.
11410b8444b9Ssam *
11420b8444b9Ssam * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
11430b8444b9Ssam */
114447fd5358SmckusickENTRY(copyoutstr, 0)
11450b8444b9Ssam	movl	12(fp),r5		# r5 = max length
1146cfd41addSmckusick	jlss	5f
11470b8444b9Ssam	movl	4(fp),r0		# r0 = kernel address
114847fd5358Smckusick	movl	8(fp),r4		# r4 = user address
114947fd5358Smckusick	andl3	$(NBPG*CLSIZE-1),r4,r2	# r2 = bytes on first page
11500b8444b9Ssam	subl3	r2,$(NBPG*CLSIZE),r2
11510b8444b9Ssam1:
11520b8444b9Ssam	cmpl	r5,r2			# r2 = min(bytes on page, length left);
11530b8444b9Ssam	jgeq	2f
11540b8444b9Ssam	movl	r5,r2
11550b8444b9Ssam2:
115647fd5358Smckusick	probew	$1,(r4),r2		# bytes accessible?
1157cfd41addSmckusick	jeql	5f
11580b8444b9Ssam	subl2	r2,r5			# update bytes left count
115947fd5358Smckusick	movl	r2,r3			# r3 = saved count
116047fd5358Smckusick	movl	r0,r1
1161bc47b33fSkarels/*
1162bc47b33fSkarels * This is a workaround for a microcode bug that causes
1163bc47b33fSkarels * a trap type 9 when cmps3/movs3 touches the last byte
1164bc47b33fSkarels * on a valid page immediately followed by an invalid page.
1165bc47b33fSkarels */
116647fd5358Smckusick#ifdef good_cmps3
116747fd5358Smckusick	cmps3				# check for null
11680b8444b9Ssam	tstl	r2
11690b8444b9Ssam	jneq	3b
117047fd5358Smckusick#else
117147fd5358Smckusick	decl	r2
117233b304f1Smckusick	beql	9f			# cannot handle case of r2 == 0!
117347fd5358Smckusick	cmps3				# check for null up to last byte
117433b304f1Smckusick9:
117547fd5358Smckusick	incl	r2
117647fd5358Smckusick	cmpl	$1,r2			# get to last byte on page?
117747fd5358Smckusick	bneq	3b
117847fd5358Smckusick	tstb	(r0)			# last byte on page null?
117933b304f1Smckusick	beql	3b
118047fd5358Smckusick	incl	r0			# not null, so bump pointer
118133b304f1Smckusick#endif not good_cmps3
118247fd5358Smckusick	subl2	r3,r0			# back up r0
118347fd5358Smckusick	movl	r4,r1
118447fd5358Smckusick	movl	r3,r2
118547fd5358Smckusick	movblk				# copy out next piece
118647fd5358Smckusick	movl	r1,r4
11870b8444b9Ssam	movl	$(NBPG*CLSIZE),r2	# check next page
11880b8444b9Ssam	tstl	r5			# run out of space?
11890b8444b9Ssam	jneq	1b
119098cc6a9fSmckusick	movl	$ENAMETOOLONG,r0	# set error code and return
119147fd5358Smckusick	jbr	6b
1192cfd41addSmckusick5:
1193cfd41addSmckusick	clrl	*$0		# this should never execute, if it does
1194cfd41addSmckusick	movl	$EFAULT,r0	#  save me a core dump (mkm - 9/87)
1195cfd41addSmckusick6:
1196cfd41addSmckusick	tstl	16(fp)
1197cfd41addSmckusick	beql	7f
1198cfd41addSmckusick	subl3	r5,12(fp),*16(fp)
1199cfd41addSmckusick7:
1200cfd41addSmckusick	ret
1201cfd41addSmckusick
12020b8444b9Ssam
12030b8444b9Ssam/*
12040b8444b9Ssam * Copy a null terminated string from one point to another in
12050b8444b9Ssam * the kernel address space.
12060b8444b9Ssam *
12070b8444b9Ssam * copystr(fromaddr, toaddr, maxlength, &lencopied)
12080b8444b9Ssam */
120947fd5358SmckusickENTRY(copystr, 0)
121047fd5358Smckusick	movl	12(fp),r3		# r3 = max length
121147fd5358Smckusick	jlss	5b
12120b8444b9Ssam	movl	4(fp),r0		# r0 = src address
121347fd5358Smckusick	movl	8(fp),r4		# r4 = dest address
121447fd5358Smckusick	clrl	r5			# r5 = bytes left
121547fd5358Smckusick	movl	r3,r2			# r2 = max bytes to copy
121647fd5358Smckusick	movl	r0,r1
121747fd5358Smckusick	cmps3				# check for null
121847fd5358Smckusick	tstl	r2
12190b8444b9Ssam	jneq	3b
122047fd5358Smckusick	subl2	r3,r0			# back up r0
122147fd5358Smckusick	movl	r4,r1
122247fd5358Smckusick	movl	r3,r2
122347fd5358Smckusick	movblk				# copy next piece
122498cc6a9fSmckusick	movl	$ENAMETOOLONG,r0	# set error code and return
122547fd5358Smckusick	jbr	6b
12260b8444b9Ssam
12270b8444b9Ssam/*
12280b8444b9Ssam * Copy a block of data from the user address space into
12290b8444b9Ssam * the kernel address space.
12300b8444b9Ssam *
12310b8444b9Ssam * copyin(fromaddr, toaddr, count)
12320b8444b9Ssam */
12330b8444b9SsamENTRY(copyin, 0)
12340b8444b9Ssam	movl	12(fp),r0		# copy length
12350b8444b9Ssam	blss	9f
12360b8444b9Ssam	movl	4(fp),r1		# copy user address
12370b8444b9Ssam	cmpl	$(CLSIZE*NBPG),r0	# probing one page or less ?
12380b8444b9Ssam	bgeq	2f			# yes
12390b8444b9Ssam1:
12400b8444b9Ssam	prober	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible ?
12410b8444b9Ssam	beql	9f			# no
12420b8444b9Ssam	addl2	$(CLSIZE*NBPG),r1	# incr user address ptr
12430b8444b9Ssam	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
12440b8444b9Ssam2:
12450b8444b9Ssam	prober	$1,(r1),r0		# bytes accessible ?
1246250e3e7bSkarels	bneq	7f			# yes
1247250e3e7bSkarels	tstl	r0			# copin 0 bytes ?
1248250e3e7bSkarels	bneq	9f			# no, can't copyin
1249250e3e7bSkarels	ret				# lie!
1250250e3e7bSkarels7:
12510b8444b9Ssam	MOVC3(4(fp),8(fp),12(fp))
12520b8444b9Ssam	clrl	r0
12530b8444b9Ssam	ret
12540b8444b9Ssam9:
12557479596bSsam	movl	$EFAULT,r0
12567479596bSsam	ret
12577479596bSsam
12580b8444b9Ssam/*
12590b8444b9Ssam * Copy a block of data from the kernel
12600b8444b9Ssam * address space to the user address space.
12610b8444b9Ssam *
12620b8444b9Ssam * copyout(fromaddr, toaddr, count)
12630b8444b9Ssam */
12640b8444b9SsamENTRY(copyout, 0)
12657479596bSsam	movl	12(fp),r0		# get count
12660b8444b9Ssam	blss	9b
12677479596bSsam	movl	8(fp),r1		# get user address
12680b8444b9Ssam	cmpl	$(CLSIZE*NBPG),r0	# can do in one probew?
12690b8444b9Ssam	bgeq	2f			# yes
12700b8444b9Ssam1:
12710b8444b9Ssam	probew	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible?
12720b8444b9Ssam	beql	9b			# no
12730b8444b9Ssam	addl2	$(CLSIZE*NBPG),r1	# increment user address
12740b8444b9Ssam	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
12750b8444b9Ssam2:
12767479596bSsam	probew	$1,(r1),r0		# bytes accessible?
1277250e3e7bSkarels	bneq	7f			# yes
1278250e3e7bSkarels	tstl	r0			# copin 0 bytes ?
1279250e3e7bSkarels	bneq	9b			# no, can't copyin
1280250e3e7bSkarels	ret				# lie!
1281250e3e7bSkarels7:
12820b8444b9Ssam	MOVC3(4(fp),8(fp),12(fp))
12837479596bSsam	clrl	r0
12847479596bSsam	ret
12857479596bSsam
12867479596bSsam/*
12874cb53c90Skarels * savectx is like setjmp but saves all registers.
12880b8444b9Ssam * Called before swapping out the u. area, restored by resume()
12890b8444b9Ssam * below.
12900b8444b9Ssam */
12910b8444b9SsamENTRY(savectx, 0)
12920b8444b9Ssam	movl	4(fp),r2
12930b8444b9Ssam	storer	$0x1ff8,(r2); addl2 $40,r2	# r3-r12
12940b8444b9Ssam	movl	(fp),(r2); addl2 $4,r2		# fp
12950b8444b9Ssam	movab	8(fp),(r2); addl2 $4,r2		# sp
12960b8444b9Ssam	movl	-8(fp),(r2)			# pc
12970b8444b9Ssam	clrl	r0
12980b8444b9Ssam	ret
12997479596bSsam
1300189fe34eSkarels#ifdef KADB
1301e281991cSsam/*
13024cb53c90Skarels * C library -- reset, setexit -- XXX
1303e281991cSsam *
1304e281991cSsam *	reset(x)
1305e281991cSsam * will generate a "return" from
1306e281991cSsam * the last call to
1307e281991cSsam *	setexit()
1308e281991cSsam * by restoring r2 - r12, fp
1309e281991cSsam * and doing a return.
1310e281991cSsam * The returned value is x; on the original
1311e281991cSsam * call the returned value is 0.
1312e281991cSsam */
1313e281991cSsamENTRY(setexit, 0)
1314e281991cSsam	movab	setsav,r0
1315e281991cSsam	storer	$0x1ffc, (r0)
1316e281991cSsam	movl	(fp),44(r0)		# fp
1317e281991cSsam	moval	4(fp),48(r0)		# sp
1318e281991cSsam	movl	-8(fp),52(r0)		# pc
1319e281991cSsam	clrl	r0
1320e281991cSsam	ret
1321e281991cSsam
1322e281991cSsamENTRY(reset, 0)
1323e281991cSsam	movl	4(fp),r0	# returned value
1324e281991cSsam	movab	setsav,r1
1325e281991cSsam	loadr	$0x1ffc,(r1)
1326e281991cSsam	movl	44(r1),fp
1327e281991cSsam	movl	48(r1),sp
1328e281991cSsam	jmp 	*52(r1)
1329e281991cSsam
1330e281991cSsam	.data
1331e281991cSsam	.align	2
1332e281991cSsamsetsav:	.space	14*4
1333e281991cSsam	.text
1334e281991cSsam#endif
1335e281991cSsam
13367479596bSsam	.globl	_whichqs
13377479596bSsam	.globl	_qs
13387479596bSsam	.globl	_cnt
13397479596bSsam
13407479596bSsam	.globl	_noproc
13417479596bSsam	.comm	_noproc,4
13427479596bSsam	.globl	_runrun
13437479596bSsam	.comm	_runrun,4
13447479596bSsam/*
13457479596bSsam * The following primitives use the fancy TAHOE instructions.
13461d771ceeSbostic * _whichqs tells which of the 32 queues _qs have processes in
13471d771ceeSbostic * them.  Setrunqueue puts processes into queues, remrq removes
13481d771ceeSbostic * them from queues.  The running process is on no queue, other
1349*bff07831Sbostic * processes are on a queue related to p->p_priority, divided by 4
13507479596bSsam * actually to shrink the 0-127 range of priorities into the 32 available
13517479596bSsam * queues.
13527479596bSsam */
13537479596bSsam
13547479596bSsam/*
13551d771ceeSbostic * setrunqueue(p), using fancy TAHOE instructions.
13567479596bSsam *
13577479596bSsam * Call should be made at spl8(), and p->p_stat should be SRUN
13587479596bSsam */
13591d771ceeSbosticENTRY(setrunqueue, 0)
13607479596bSsam	movl	4(fp),r0
1361*bff07831Sbostic	tstl	P_BACK(r0)		## firewall: p->p_back must be 0
13627479596bSsam	beql	set1			##
13637479596bSsam	pushab	set3			##
13647479596bSsam	callf	$8,_panic		##
13657479596bSsamset1:
1366*bff07831Sbostic	movzbl	P_PRIORITY(r0),r1	# put on p->p_pri / 4 queue
13677479596bSsam	shar	$2,r1,r1
13687479596bSsam	shal	$1,r1,r2
13697479596bSsam	moval	_qs[r2],r2
13707479596bSsam	insque	(r0),*4(r2)		# at end of queue
13717479596bSsam	shal	r1,$1,r1
13727479596bSsam	orl2	r1,_whichqs		# mark queue non-empty
13737479596bSsam	ret
13747479596bSsam
13751d771ceeSbosticset3:	.asciz	"setrunqueue"
13767479596bSsam
13777479596bSsam/*
13787479596bSsam * remrq(p), using fancy TAHOE instructions
13797479596bSsam *
13807479596bSsam * Call should be made at spl8().
13817479596bSsam */
13820b8444b9SsamENTRY(remrq, 0)
13837479596bSsam	movl	4(fp),r0
1384*bff07831Sbostic	movzbl	P_PRIORITY(r0),r1
13857479596bSsam	shar	$2,r1,r1
13867479596bSsam	bbs	r1,_whichqs,rem1
13877479596bSsam	pushab	rem3			# it wasn't recorded to be on its q
13887479596bSsam	callf	$8,_panic
13897479596bSsamrem1:
13907479596bSsam	remque	(r0)
13917479596bSsam	bneq	rem2			# q not empty yet
13927479596bSsam	shal	r1,$1,r1
13937479596bSsam	mcoml	r1,r1
13947479596bSsam	andl2	r1,_whichqs		# mark queue empty
13957479596bSsamrem2:
1396*bff07831Sbostic	clrl	P_BACK(r0)		## for firewall checking
13977479596bSsam	ret
13987479596bSsam
13997479596bSsamrem3:	.asciz	"remrq"
14007479596bSsam
14017479596bSsam/*
14027479596bSsam * Masterpaddr is the p->p_addr of the running process on the master
14037479596bSsam * processor.  When a multiprocessor system, the slave processors will have
14047479596bSsam * an array of slavepaddr's.
14057479596bSsam */
14067479596bSsam	.globl	_masterpaddr
14077479596bSsam	.data
1408e281991cSsam	.align	2
14090b8444b9Ssam_masterpaddr: .long	0
14107479596bSsam
14117479596bSsam	.text
1412*bff07831Sbosticsw0:	.asciz	"Xswitch"
1413844a1895Skarels
1414844a1895Skarels/*
1415*bff07831Sbostic * When no processes are on the runq, Xswitch branches to idle
1416844a1895Skarels * to wait for something to come ready.
1417844a1895Skarels */
1418844a1895Skarels	.globl  Idle
1419844a1895SkarelsIdle: idle:
1420717b2398Skarels	movl	$1,_noproc
1421844a1895Skarels	mtpr	$0,$IPL			# must allow interrupts here
1422844a1895Skarels1:
1423844a1895Skarels	tstl	_whichqs		# look for non-empty queue
1424844a1895Skarels	bneq	sw1
1425844a1895Skarels	brb	1b
1426844a1895Skarels
1427844a1895Skarelsbadsw:	pushab	sw0
1428844a1895Skarels	callf	$8,_panic
1429844a1895Skarels	/* NOTREACHED */
1430844a1895Skarels
1431844a1895Skarels	.align	2
14327479596bSsam/*
1433*bff07831Sbostic * Xswitch(), using fancy tahoe instructions
14347479596bSsam */
1435*bff07831SbosticENTRY(Xswitch, 0)
14367479596bSsam	movl	(fp),fp			# prepare for rei
14377479596bSsam	movl	(sp),4(sp)		# saved pc
14387479596bSsam	tstl	(sp)+
14397479596bSsam	movpsl	4(sp)
1440844a1895Skarels	incl	_cnt+V_SWTCH
14417479596bSsamsw1:	ffs	_whichqs,r0		# look for non-empty queue
1442844a1895Skarels	blss	idle			# if none, idle
1443844a1895Skarels	mtpr	$0x18,$IPL		# lock out all so _whichqs==_qs
1444844a1895Skarels	bbc	r0,_whichqs,sw1		# proc moved via interrupt
14457479596bSsam	shal	$1,r0,r1
14467479596bSsam	moval	_qs[r1],r1
14477479596bSsam	movl	(r1),r2			# r2 = p = highest pri process
14487479596bSsam	remque	*(r1)
1449844a1895Skarels	bvs	badsw			# make sure something was there
1450844a1895Skarels	bneq	sw2
14517479596bSsam	shal	r0,$1,r1
14527479596bSsam	mcoml	r1,r1
14537479596bSsam	andl2	r1,_whichqs		# no more procs in this queue
1454844a1895Skarelssw2:
14557479596bSsam	clrl	_noproc
1456844a1895Skarels	clrl	_runrun
1457717b2398Skarels#ifdef notdef
14587479596bSsam	tstl	P_WCHAN(r2)		## firewalls
1459844a1895Skarels	bneq	badsw			##
14608306c720Ssam	cmpb	P_STAT(r2),$SRUN	##
1461844a1895Skarels	bneq	badsw			##
1462717b2398Skarels#endif
1463*bff07831Sbostic	clrl	P_BACK(r2)		##
14647479596bSsam	movl	*P_ADDR(r2),r0
14650b8444b9Ssam#ifdef notdef
1466844a1895Skarels	cmpl	r0,_masterpaddr		# resume of current proc is easy
14670b8444b9Ssam	beql	res0
14680b8444b9Ssam#endif
1469844a1895Skarels	movl	r0,_masterpaddr
1470844a1895Skarels	shal	$PGSHIFT,r0,r0		# r0 = pcbb(p)
14717479596bSsam	brb	swresume
14727479596bSsam
14737479596bSsam/*
14747479596bSsam * resume(pf)
14757479596bSsam */
14760b8444b9SsamENTRY(resume, 0)
14770b8444b9Ssam	shal	$PGSHIFT,4(fp),r0	# r0 = pcbb(pf)
14787479596bSsam	movl	(fp),fp			# prepare for rei
14797479596bSsam	movl	(sp)+,4(sp)		# saved pc
14807479596bSsam	tstl	(sp)+
14817479596bSsam	movpsl	4(sp)
14827479596bSsamswresume:
14837479596bSsam	mtpr	$0x18,$IPL		# no interrupts, please
14847479596bSsam	movl	_CMAP2,_u+PCB_CMAP2	# yech
14857479596bSsam	REST_ACC			# restore original accumulator
14867479596bSsam	svpctx
14877479596bSsam	mtpr	r0,$PCBB
14887479596bSsam	ldpctx
14897479596bSsam	movl	_u+PCB_CMAP2,_CMAP2	# yech
14907479596bSsam	mtpr	$_CADDR2,$TBIS
14917479596bSsamres0:
14920b8444b9Ssam	movl	_u+U_PROCP,r2		# r2 = u.u_procp
14930b8444b9Ssam	tstl	P_CKEY(r2)		# does proc have code key?
14940b8444b9Ssam	bneq	1f
14950b8444b9Ssam	callf	$4,_getcodekey		# no, give him one
14968306c720Ssam	movl	_u+U_PROCP,r2		# r2 = u.u_procp
14970b8444b9Ssam	movl	r0,P_CKEY(r2)
14980b8444b9Ssam1:
14990b8444b9Ssam	tstl	P_DKEY(r2)		# does proc have data key?
15000b8444b9Ssam	bneq	1f
15010b8444b9Ssam	callf	$4,_getdatakey		# no, give him one
15028306c720Ssam	movl	_u+U_PROCP,r2		# r2 = u.u_procp
15030b8444b9Ssam	movl	r0,P_DKEY(r2)
15040b8444b9Ssam1:
15050b8444b9Ssam	mtpr	P_CKEY(r2),$CCK		# set code cache key
15060b8444b9Ssam	mtpr	P_DKEY(r2),$DCK		# set data cache key
15077479596bSsam	tstl	_u+PCB_SSWAP
15080b8444b9Ssam	bneq	res1
15090b8444b9Ssam	rei
15104cb53c90Skarelsres1:					# restore alternate saved context
15117479596bSsam	movl	_u+PCB_SSWAP,r2
15127479596bSsam	clrl	_u+PCB_SSWAP
15130b8444b9Ssam	loadr	$0x3ff8,(r2); addl2 $44,r2	# restore r3-r13 (r13=fp)
15140b8444b9Ssam	movl	(r2),r1; addl2 $4,r2	# fetch previous sp ...
15150b8444b9Ssam	movab	(sp),r0			# ... and current sp and
15160b8444b9Ssam	cmpl	r1,r0			# check for credibility,
15170b8444b9Ssam	bgequ	1f			# if further up stack ...
15180b8444b9Ssam	pushab 2f; callf $8,_panic	# ... panic
15190b8444b9Ssam	/*NOTREACHED*/
15200b8444b9Ssam1:					# sp ok, complete return
15210b8444b9Ssam	movl	r1,sp			# restore sp
1522c1693b91Smckusick	pushl	$PSL_PRVMOD		# kernel mode, ipl 0
1523c1693b91Smckusick	pushl	(r2)			# return address
15247479596bSsam	rei
15250b8444b9Ssam2:	.asciz	"ldctx"
15267479596bSsam
15277479596bSsam/*
15287479596bSsam * {fu,su},{byte,word}
15297479596bSsam */
15300b8444b9SsamENTRY(fuword, 0)
15317479596bSsam	movl	4(fp), r1
15327479596bSsam	prober	$1,(r1),$4		# check access
15337479596bSsam	beql	fserr			# page unreadable
15347479596bSsam	bitl	$1,r1			# check byte alignment
15357479596bSsam	bneq	2f			# odd, do byte-word-byte
15367479596bSsam	bitl	$2,r1			# check word alignment
15377479596bSsam	bneq	1f			# odd, do in 2 words
15387479596bSsam	movl	(r1),r0			# move longword
15397479596bSsam	ret
15407479596bSsam1:
15417479596bSsam	movw	(r1),r0			# move two words
15427479596bSsam	shal	$16,r0,r0
15437479596bSsam	movzwl	2(r1),r1		# orw2 sign extends
15447479596bSsam	orl2	r1,r0
15457479596bSsam	ret
15467479596bSsam2:
15477479596bSsam	movb	(r1),r0			# move byte-word-byte
15487479596bSsam	shal	$24,r0,r0
15497479596bSsam	movzwl	1(r1),r2		# orw2 sign extends
15507479596bSsam	shal	$8,r2,r2
15517479596bSsam	movzbl	3(r1),r1		# orb2 sign extends
15527479596bSsam	orl2	r2,r1
15537479596bSsam	orl2	r1,r0
15547479596bSsam	ret
15557479596bSsamfserr:
15567479596bSsam	mnegl	$1,r0
15577479596bSsam	ret
15587479596bSsam
15590b8444b9SsamENTRY(fubyte, 0)
15607479596bSsam	prober	$1,*4(fp),$1
15617479596bSsam	beql	fserr
15627479596bSsam	movzbl	*4(fp),r0
15637479596bSsam	ret
15647479596bSsam
15650b8444b9SsamENTRY(suword, 0)
15667479596bSsam	movl	4(fp), r0
15677479596bSsam	probew	$1,(r0),$4		# check access
15687479596bSsam	beql	fserr			# page unwritable
15697479596bSsam	bitl	$1,r0			# check byte alignment
15707479596bSsam	bneq	1f			# odd byte boundary
15717479596bSsam	bitl	$2,r0			# check word alignment
15727479596bSsam	beql	2f			# longword aligned
15737479596bSsam	movw	8(fp),(r0)		# move two words
15747479596bSsam	movw	10(fp),2(r0)
15757479596bSsam	jbr	3f
15767479596bSsam1:
15777479596bSsam	movb	8(fp),(r0)
15787479596bSsam	movb	9(fp),1(r0)
15797479596bSsam	movb	10(fp),2(r0)
15807479596bSsam	movb	11(fp),3(r0)
15817479596bSsam	jbr	3f
15827479596bSsam2:
15837479596bSsam	movl	8(fp),(r0)
15847479596bSsam3:
15857479596bSsam	clrl	r0
15867479596bSsam	ret
15877479596bSsam
15880b8444b9SsamENTRY(subyte, 0)
15897479596bSsam	probew	$1,*4(fp),$1
15907479596bSsam	beql	fserr
15917479596bSsam	movb	11(fp),*4(fp)
15927479596bSsam	clrl	r0
15937479596bSsam	ret
15947479596bSsam
15957479596bSsam/*
15967479596bSsam * Copy 1 relocation unit (NBPG bytes)
15977479596bSsam * from user virtual address to physical address
15987479596bSsam */
15990b8444b9SsamENTRY(copyseg, 0)
16007479596bSsam	orl3	$PG_V|PG_KW,8(fp),_CMAP2
16017479596bSsam	mtpr	$_CADDR2,$TBIS	# invalidate entry for copy
16020b8444b9Ssam	MOVC3(4(fp),$_CADDR2,$NBPG)
16037479596bSsam	ret
16047479596bSsam
16057479596bSsam/*
16060b8444b9Ssam * Clear a page of memory.  The page frame is specified.
16077479596bSsam *
16080b8444b9Ssam * clearseg(pf);
16097479596bSsam */
16100b8444b9SsamENTRY(clearseg, 0)
16117479596bSsam	orl3	$PG_V|PG_KW,4(fp),_CMAP1	# Maps to virtual addr CADDR1
16127479596bSsam	mtpr	$_CADDR1,$TBIS
16137479596bSsam	movl	$255,r0				# r0 = limit
16147479596bSsam	clrl	r1				# r1 = index of cleared long
16157479596bSsam1:
16167479596bSsam	clrl	_CADDR1[r1]
16177479596bSsam	aobleq	r0,r1,1b
16187479596bSsam	ret
16197479596bSsam
16207479596bSsam/*
16210b8444b9Ssam * Check user mode read/write access.
16220b8444b9Ssam *
16230b8444b9Ssam * useracc(addr, count, mode)
16240b8444b9Ssam *	caddr_t addr; int count, mode;
16250b8444b9Ssam * mode = 0	write access
16260b8444b9Ssam * mode = 1	read access
16277479596bSsam */
16280b8444b9SsamENTRY(useracc, 0)
16297479596bSsam	movl	$1,r2			# r2 = 'user mode' for probew/probew
16307479596bSsamprobes:
16317479596bSsam	movl	4(fp),r0		# get va
16327479596bSsam	movl	8(fp),r1		# count
16337479596bSsam	tstl	12(fp)			# test for read access ?
16347479596bSsam	bneq	userar			# yes
16350b8444b9Ssam	cmpl	$(CLSIZE*NBPG),r1	# can we do it in one probe ?
16367479596bSsam	bgeq	uaw2			# yes
16377479596bSsamuaw1:
16380b8444b9Ssam	probew	r2,(r0),$(CLSIZE*NBPG)
16397479596bSsam	beql	uaerr			# no access
16400b8444b9Ssam	addl2	$(CLSIZE*NBPG),r0
16410b8444b9Ssam	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1)
16427479596bSsamuaw2:
16437479596bSsam	probew	r2,(r0),r1
16447479596bSsam	beql	uaerr
16457479596bSsam	movl	$1,r0
16467479596bSsam	ret
16477479596bSsamuserar:
16480b8444b9Ssam	cmpl	$(CLSIZE*NBPG),r1
16497479596bSsam	bgeq	uar2
16507479596bSsamuar1:
16510b8444b9Ssam	prober	r2,(r0),$(CLSIZE*NBPG)
16527479596bSsam	beql	uaerr
16530b8444b9Ssam	addl2	$(CLSIZE*NBPG),r0
16540b8444b9Ssam	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1)
16557479596bSsamuar2:
16567479596bSsam	prober	r2,(r0),r1
16577479596bSsam	beql	uaerr
16587479596bSsam	movl	$1,r0
16597479596bSsam	ret
16607479596bSsamuaerr:
16617479596bSsam	clrl	r0
16627479596bSsam	ret
16637479596bSsam
16647479596bSsam/*
16650b8444b9Ssam * Check kernel mode read/write access.
16660b8444b9Ssam *
16670b8444b9Ssam * kernacc(addr, count, mode)
16680b8444b9Ssam *	caddr_t addr; int count, mode;
16690b8444b9Ssam * mode = 0	write access
16700b8444b9Ssam * mode = 1	read access
16717479596bSsam */
16720b8444b9SsamENTRY(kernacc, 0)
16737479596bSsam	clrl	r2		# r2 = 0 means kernel mode probe.
16747479596bSsam	jbr	probes		# Dijkstra would get gastric distress here.
16757479596bSsam
16767479596bSsam/*
16777479596bSsam * addupc - increment some histogram counter
16787479596bSsam *	in the profiling buffer
16797479596bSsam *
16800b8444b9Ssam * addupc(pc, prof, delta)
16810b8444b9Ssam *	long pc; short delta; struct uprof *prof;
16827479596bSsam *
16837479596bSsam * struct uprof {		# profile arguments
16847479596bSsam * 	short	*r_base;	# buffer base
16857479596bSsam * 	unsigned pr_size;	# buffer size
16867479596bSsam * 	unsigned pr_off;	# pc offset
16877479596bSsam * 	unsigned pr_scale;	# pc scaling
16887479596bSsam * }
16897479596bSsam */
16900b8444b9SsamENTRY(addupc, 0)
16917479596bSsam	movl	8(fp),r2		# r2 points to structure
16927479596bSsam	subl3	8(r2),4(fp),r0		# r0 = PC - lowpc
16937479596bSsam	jlss	9f			# PC < lowpc , out of range !
16947479596bSsam	shrl	$1,r0,r0		# the unit is words
16957479596bSsam	shrl	$1,12(r2),r1		# ditto for scale
16967479596bSsam	emul	r1,r0,$0,r0
16977479596bSsam	shrq	$14,r0,r0
16987479596bSsam	tstl	r0			# too big
16997479596bSsam	jneq	9f
17007479596bSsam	cmpl	r1,4(r2)		# Check buffer overflow
17017479596bSsam	jgequ	9f
17027479596bSsam	probew	$1,*0(r2)[r1],$2	# counter accessible?
17037479596bSsam	jeql	9f
17047479596bSsam	shrl	$1,r1,r1		# make r1 word index
17057479596bSsam	addw2	14(fp),*0(r2)[r1]
17067479596bSsam9:	ret
17070b8444b9Ssam
17080b8444b9Ssam/*
17090b8444b9Ssam * scanc(size, cp, table, mask)
17100b8444b9Ssam */
17110b8444b9SsamENTRY(scanc, R3|R4)
17120b8444b9Ssam	movl	8(fp),r0		# r0 = cp
17130b8444b9Ssam	addl3	4(fp),r0,r2		# end = &cp[size]
17140b8444b9Ssam	movl	12(fp),r1		# r1 = table
17150b8444b9Ssam	movb	19(fp),r4		# r4 = mask
17160b8444b9Ssam	decl	r0			# --cp
17170b8444b9Ssam	jbr	0f			# just like Fortran...
17180b8444b9Ssam1:					# do {
17190b8444b9Ssam	movzbl	(r0),r3
17200b8444b9Ssam	bitb	r4,(r1)[r3]		#	if (table[*cp] & mask)
17210b8444b9Ssam	jneq	2f			#		break;
17220b8444b9Ssam0:	aoblss	r2,r0,1b		# } while (++cp < end);
17230b8444b9Ssam2:
17240b8444b9Ssam	subl3	r0,r2,r0; ret		# return (end - cp);
17250b8444b9Ssam
17260b8444b9Ssam/*
17270b8444b9Ssam * skpc(mask, size, cp)
17280b8444b9Ssam */
17290b8444b9SsamENTRY(skpc, 0)
17300b8444b9Ssam	movl	12(fp),r0		# r0 = cp
17310b8444b9Ssam	addl3	8(fp),r0,r1		# r1 = end = &cp[size];
17320b8444b9Ssam	movb	7(fp),r2		# r2 = mask
17330b8444b9Ssam	decl	r0			# --cp;
17340b8444b9Ssam	jbr	0f
17350b8444b9Ssam1:					# do
17360b8444b9Ssam	cmpb	(r0),r2			#	if (*cp != mask)
17370b8444b9Ssam	jneq	2f			#		break;
17380b8444b9Ssam0:	aoblss	r1,r0,1b		# while (++cp < end);
17390b8444b9Ssam2:
17400b8444b9Ssam	subl3	r0,r1,r0; ret		# return (end - cp);
17410b8444b9Ssam
17420b8444b9Ssam/*
17430b8444b9Ssam * locc(mask, size, cp)
17440b8444b9Ssam */
17450b8444b9SsamENTRY(locc, 0)
17460b8444b9Ssam	movl	12(fp),r0		# r0 = cp
17470b8444b9Ssam	addl3	8(fp),r0,r1		# r1 = end = &cp[size]
17480b8444b9Ssam	movb	7(fp),r2		# r2 = mask
17490b8444b9Ssam	decl	r0			# --cp;
17500b8444b9Ssam	jbr	0f
17510b8444b9Ssam1:					# do
17520b8444b9Ssam	cmpb	(r0),r2			#	if (*cp == mask)
17530b8444b9Ssam	jeql	2f			#		break;
17540b8444b9Ssam0:	aoblss	r1,r0,1b		# while (++cp < end);
17550b8444b9Ssam2:
17560b8444b9Ssam	subl3	r0,r1,r0; ret		# return (end - cp);
17579dab7c56Ssam
175863a4e097Ssam#ifdef ALIGN
1759d357015aSbostic#include "tahoe/align/align.h"
17609dab7c56Ssam
17619dab7c56Ssam	.globl	_alignment
17629dab7c56Ssam/*
17639dab7c56Ssam * There's an intimate relationship between this piece of code
17649dab7c56Ssam * and the alignment emulation code (especially the layout
17659dab7c56Ssam * of local variables in alignment.c! Don't change unless
17669dab7c56Ssam * you update both this, alignment.h and alignment.c !!
17679dab7c56Ssam */
17689dab7c56Ssamnon_aligned:
17699dab7c56Ssam	orb2	$EMULATEALIGN,_u+U_EOSYS
17709dab7c56Ssam	incl	_cnt+V_TRAP
17719dab7c56Ssam	incl	_cnt+V_ALIGN		# count emulated alignment traps
17729dab7c56Ssam	moval	4(sp),_user_psl
17739dab7c56Ssam	SAVE_FPSTAT(4)			# Also zeroes out ret_exception !
17749dab7c56Ssam	pushl	$0			# ret_addr
17759dab7c56Ssam	pushl	$0			# ret_code
17769dab7c56Ssam	mfpr	$USP,-(sp)		# user sp
17779dab7c56Ssam	callf	$4,_alignment		# call w/o parms so regs may be modified
17789dab7c56Ssam	/*
17799dab7c56Ssam	 * We return here after a successful emulation or an exception.
17809dab7c56Ssam	 * The registers have been restored and we must not alter them
17819dab7c56Ssam	 * before returning to the user.
17829dab7c56Ssam	 */
17839dab7c56Ssam2:	mtpr	(sp)+,$USP		# restore user sp
17849dab7c56Ssam	tstl	8(sp)			# Any exception ?
17859dab7c56Ssam	bneq	got_excp		# Yes, reflect it back to user.
17869dab7c56Ssam	moval	8(sp),sp		# pop 2 zeroes pushed above
17879dab7c56Ssam	REST_FPSTAT
17889dab7c56Ssam	xorb2	$EMULATEALIGN,_u+U_EOSYS
17899dab7c56Ssam
17909dab7c56Ssam	bitl	$PSL_T,4(sp)		# check for trace bit set
17919dab7c56Ssam	beql	9f
17929dab7c56Ssam	CHECK_SFE(4)
17939dab7c56Ssam	pushl $0
17949dab7c56Ssam	SAVE_FPSTAT(8)
17959dab7c56Ssam	TRAP(TRCTRAP)
17969dab7c56Ssam9:	rei
17979dab7c56Ssam
17989dab7c56Ssamgot_excp:				# decode exception
17999dab7c56Ssam	casel	8(sp),$ILL_ADDRMOD,$ALIGNMENT
18009dab7c56Ssam	.align	1
18019dab7c56SsamL1:
18029dab7c56Ssam	.word	ill_addrmod-L1
18039dab7c56Ssam	.word	ill_access-L1
18049dab7c56Ssam	.word	ill_oprnd-L1
18059dab7c56Ssam	.word	arithmetic-L1
18069dab7c56Ssam	.word	alignment-L1
18079dab7c56Ssam	brw	alignment		# default - shouldn't come here at all !
18089dab7c56Ssam
18099dab7c56Ssamill_addrmod:				# No other parameters. Set up stack as
18109dab7c56Ssam	moval	8(sp),sp		# the HW would do it in a real case.
18119dab7c56Ssam	REST_FPSTAT
18129dab7c56Ssam	jbr	_Xresadflt
18139dab7c56Ssamill_oprnd:
18149dab7c56Ssam	moval	8(sp),sp
18159dab7c56Ssam	REST_FPSTAT
18169dab7c56Ssam	jbr	_Xresopflt
18179dab7c56Ssamalignment:
18189dab7c56Ssam	moval	8(sp),sp
18199dab7c56Ssam	REST_FPSTAT
18209dab7c56Ssam	jbr	align_excp	# NB: going to _Xalignflt would cause loop
18219dab7c56Ssamill_access:
18229dab7c56Ssam	/*
18239dab7c56Ssam	 * Must restore accumulator w/o modifying sp and w/o using
18249dab7c56Ssam	 * registers.  Solution: copy things needed by REST_FPSTAT.
18259dab7c56Ssam	 */
18269dab7c56Ssam	pushl	20(sp)			# The flags longword
18279dab7c56Ssam	pushl	20(sp)			# acc_low
18289dab7c56Ssam	pushl	20(sp)			# acc_high
18299dab7c56Ssam	pushl	20(sp)			# ret_exception ignored by REST_FPSTAT
18309dab7c56Ssam	REST_FPSTAT			# Back where we were with the sp !
18319dab7c56Ssam	movl	(sp),16(sp)		# code for illegal access
18329dab7c56Ssam	movl	4(sp),20(sp)		# original virtual address
18339dab7c56Ssam	moval	16(sp),sp		# Just like the HW would set it up
18349dab7c56Ssam	jbr	_Xprotflt
18359dab7c56Ssamarithmetic:				# same trickery as above
18369dab7c56Ssam	pushl	20(sp)			# The flags longword
18379dab7c56Ssam	pushl	20(sp)			# acc_low
18389dab7c56Ssam	pushl	20(sp)			# acc_high
18399dab7c56Ssam	pushl	20(sp)			# ret_exception ignored by REST_FPSTAT
18409dab7c56Ssam	REST_FPSTAT			# Back where we were with the sp !
18419dab7c56Ssam	movl	(sp),20(sp)		# code for arithmetic exception
18429dab7c56Ssam	moval	20(sp),sp		# Just like the HW would set it up
18439dab7c56Ssam	jbr	_Xarithtrap
18449dab7c56Ssam#endif
1845