xref: /original-bsd/sys/tahoe/tahoe/locore.s (revision a2cda15f)
1/*	locore.s	1.24	88/02/28	*/
2
3#include "../tahoe/mtpr.h"
4#include "../tahoe/trap.h"
5#include "../tahoe/psl.h"
6#include "../tahoe/pte.h"
7#include "../tahoe/cp.h"
8#include "../tahoe/mem.h"
9#include "../tahoe/SYS.h"
10#include "../tahoemath/fp.h"
11
12#include "errno.h"
13#include "syscall.h"
14#include "cmap.h"
15
16	.set	HIGH,0x1f		# mask for total disable
17	.set	NISP,3			# number of interrupt stack pages
18	.set	SYSTEM,0xC0000000	# virtual address of system start
19	.set	PPAGES,0x100000  	# possible pages in P0,P1, etc.
20
21/* ACBL for non-negative '_add' */
22#define ACBL(_limit,_add,_index,_displ) \
23	addl2	_add,_index; \
24	cmpl	_index,_limit; \
25	bleq	_displ
26
27/* _ACBL for negative '_add' */
28#define _ACBL(_limit,_add,_index,_displ) \
29	addl2	_add,_index; \
30	cmpl	_index,_limit; \
31	bgeq	_displ
32
33#define	MOVC3(_srcaddr,_dstaddr,_len) \
34	movl	_srcaddr,r0; \
35	movl	_dstaddr,r1; \
36	movl	_len,r2; \
37	movblk
38
39/* keep address of psl if coming from user mode */
40#define CHECK_SFE(_delta) \
41	bitl	$PSL_CURMOD,_delta(sp); \
42	jeql	1f; \
43	moval	_delta(sp),_user_psl; \
441:
45
46/*
47 * User structure is UPAGES at top of user space.
48 */
49	.globl	_u
50	.set	_u,SYSTEM - UPAGES*NBPG
51
52/*
53 * Restart stack. Used on power recovery or panic.
54 * Takes a core-dump and then halts.
55 */
56	.globl	_rsstk
57	.globl	pwfl_stk
58_rsstk:
59	.space	1024-8
60pwfl_stk:
61	.space	4
62dumpflag:
63	.space	4
64
65	.globl	_intstack
66_intstack:
67	.space	NISP*NBPG
68eintstack:
69
70/*
71 * Power failure storage block and
72 * macros for saving and restoring.
73 */
74#define	POWERFAIL(id,longs) \
75	.globl	pwfl_/**/id \
76pwfl_/**/id: .space longs*4
77	.data
78	POWERFAIL(r0,	14)		# r0-r13
79	POWERFAIL(sp,	1)		# r14
80	POWERFAIL(SCBB,	1)		# system control block base
81	POWERFAIL(SBR,	1)		# system pte base
82	POWERFAIL(SLR,	1)		# system pte length
83	POWERFAIL(P0BR,	1)		# p0 pte base
84	POWERFAIL(P0LR,	1)		# p0 pte length
85	POWERFAIL(P1BR,	1)		# p1 pte base
86	POWERFAIL(P1LR,	1)		# p1 pte length
87	POWERFAIL(P2BR,	1)		# p2 pte base
88	POWERFAIL(P2LR,	1)		# p2 pte length
89	POWERFAIL(IPL,	1)		# interrupt priority level
90	POWERFAIL(DCK,	1)		# data cache key
91	POWERFAIL(CCK,	1)		# code cache key
92	POWERFAIL(PCBB,	1)		# process control block base
93	POWERFAIL(ISP,	1)		# interrupt stack pointer
94	POWERFAIL(KSP,	1)		# kernel mode stack pointer
95	POWERFAIL(USP,	1)		# user mode stack pointer
96	POWERFAIL(MME,	1)		# memory management enable
97	POWERFAIL(PSL,	1)		# processor status longword
98
99/*
100 * Save current state in power fail storage block.
101 */
102#define	SAVEpwfl() \
103	movpsl	pwfl_PSL	# Keeps all flags, etc. \
104	storer	$0x3fff,pwfl_r0	# Saves r0-r13 \
105	moval	0(sp),pwfl_sp	# Saves sp (=r14) \
106	mfpr	$SBR,pwfl_SBR	# Save all re_loadable registers \
107	mfpr	$SLR,pwfl_SLR \
108	mfpr	$P0BR,pwfl_P0BR \
109	mfpr	$P0LR,pwfl_P0LR \
110	mfpr	$P1BR,pwfl_P1BR \
111	mfpr	$P1LR,pwfl_P1LR \
112	mfpr	$P2BR,pwfl_P2BR \
113	mfpr	$P2LR,pwfl_P2LR \
114	mfpr	$IPL,pwfl_IPL \
115	mfpr	$MME,pwfl_MME \
116	mfpr	$DCK,pwfl_DCK \
117	mfpr	$CCK,pwfl_CCK \
118	mfpr	$PCBB,pwfl_PCBB \
119	mfpr	$ISP,pwfl_ISP \
120	mfpr	$SCBB,pwfl_SCBB \
121	mfpr	$KSP,pwfl_KSP \
122	mfpr	$USP,pwfl_USP
123
124/*
125 * Restore state saved in power fail block and
126 * jmp to location specified after (possibly)
127 * enabling memory management.
128 */
129#define	RESTOREpwfl(loc) \
130	loadr	$0x3fff,pwfl_r0	# Restore r0-r13 \
131	movl	pwfl_sp,sp	# Restore sp (=r14) \
132	mtpr	pwfl_SCBB,$SCBB \
133	mtpr	pwfl_SBR,$SBR	# Restore all re_loadable registers \
134	mtpr	pwfl_SLR,$SLR \
135	mtpr	pwfl_P0BR,$P0BR \
136	mtpr	pwfl_P0LR,$P0LR \
137	mtpr	pwfl_P1BR,$P1BR \
138	mtpr	pwfl_P1LR,$P1LR \
139	mtpr	pwfl_P2BR,$P2BR \
140	mtpr	pwfl_P2LR,$P2LR \
141	mtpr	pwfl_IPL,$IPL \
142	mtpr	pwfl_DCK,$DCK \
143	mtpr	pwfl_CCK,$CCK \
144	mtpr	pwfl_PCBB,$PCBB \
145	mtpr	pwfl_ISP,$ISP \
146	mtpr	pwfl_KSP,$KSP \
147	mtpr	pwfl_USP,$USP \
148\
149	bicpsw	$0xff		# Restore PSW. \
150	bispsw	pwfl_PSL+2	# Set original bits back (just in case..) \
151# now go to mapped mode \
152# Have to change PC to system addresses \
153	mtpr	$1,$PACC	# Thoroughly clean up caches. \
154	mtpr	$1,$PADC \
155	mtpr	$1,$TBIA \
156	mtpr	pwfl_MME,$MME  	# Restore MME. Last thing to be done. \
157	jmp 	loc
158
159/*
160 * Do a dump.
161 * Called by auto-restart.
162 * May be called manually.
163 */
164	.align	2
165	.text
166	.globl	_Xdoadump
167	.globl	_doadump
168_Xdoadump:					# CP comes here after power fail
169	RESTOREpwfl(*0f)			# restore state
170_doadump:
171	.word 0
1720:	mtpr	$HIGH,$IPL
173#define	_rsstkmap _Sysmap+12	# powerfail storage, scb, rsstk, int stack
174	tstl	dumpflag			# dump only once!
175	bneq	1f
176	andl2	$~PG_PROT,_rsstkmap
177	orl2	$PG_KW,_rsstkmap		# Make dump stack r/w
178	mtpr	$0,$TBIA
179	movl	$1,dumpflag
180	movab	dumpflag,sp
181	callf	$4,_dumpsys
1821:
183	halt
184
185/*
186 * Interrupt vector routines
187 */
188	.globl	_waittime
189#define	SCBVEC(name) \
190	.align 2; \
191	.globl _X/**/name; \
192_X/**/name
193#define	PANIC(msg) \
194	clrl _waittime; pushab 1f; callf $8,_panic; 1: .asciz msg
195#define	PRINTF(n,msg) \
196	pushab 1f; callf $(n+2)*4,_printf; MSG(msg)
197#define	MSG(msg) .data; 1: .asciz msg; .text
198/*
199 * r0-r5 are saved across all faults and interrupts.
200 * Routines below and those hidden in vbglue.s (device
201 * interrupts) invoke the PUSHR/POPR macros to execute
202 * this.  Also, certain stack frame offset calculations
203 * use this, using the REGSPC definition (and FPSPC defined below).
204 */
205#define	REGSPC	6*4
206#define	PUSHR	movab -REGSPC(sp),sp; storer $0x3f,(sp)
207#define	POPR	loadr $0x3f,(sp); movab REGSPC(sp),sp
208
209/*
210 * Floating point state is saved across faults and
211 * interrupts.  The state occupies 4 longwords on
212 * the stack:
213 *	precision indicator (single = 0/double = 1)
214 *	double representation of accumulator
215 *	save accumulator status flag (pcb_savacc)
216 */
217#define	FPSPC	(4*4)
218
219#define SAVE_FPSTAT(_delta) \
220	bitl	$PSL_DBL,_delta(sp); \
221	beql	1f; \
222	pushl	$1; \
223	pushd; \
224	jmp	2f; \
2251:	pushl	$0; \
226	pushl	$0; \
227	stf	-(sp); \
2282:	tstl	_u+PCB_SAVACC; \
229	bneq	3f; \
230	moval	0(sp),_u+PCB_SAVACC; \
231	orl2	$2,8(sp);\
2323:	pushl	$0;
233
234#define REST_FPSTAT \
235	tstl	(sp)+; \
236	bitl	$2,8(sp);\
237	beql	1f;\
238	movl	$0,_u+PCB_SAVACC; \
2391:	bitl	$1,8(sp); \
240	beql	2f; \
241	ldd	(sp); \
242	jmp	3f; \
2432:	ldf	(sp); \
2443:	moval	12(sp),sp;
245
246#define REST_ACC \
247	tstl	_u+PCB_SAVACC; \
248	beql	2f; \
249	movl	_u+PCB_SAVACC,r1; \
250	andl3	$(EXPMASK|SIGNBIT),(r1),-(sp); \
251	cmpl	$0x80000000,(sp)+; \
252	bneq	3f; \
253	clrl	(r1); \
2543:	bitl	$1,8(r1); \
255	beql	1f; \
256	ldd	(r1); \
257	jmp	2f; \
2581:	ldf	(r1); \
2592:	;
260
261	.data
262nofault: .space	4			# bus error non-local goto label
263
264	.text
265SCBVEC(buserr):
266	CHECK_SFE(12)
267	SAVE_FPSTAT(12)
268	incl	_intrcnt+I_BUSERR	# keep stats...
269	pushl	r0			# must save
270	andl3	24(sp),$ERRCD,r0	# grab pushed MER value
271	cmpl	r0,$APE			# address parity error?
272	jneq	1f
273	halt
2741:	cmpl	r0,$VBE			# versabus error?
275	jneq	2f
276	halt
2772:
278	movl	(sp)+,r0		# restore r0 and...
279	bitl	$PSL_CURMOD,4*4+3*4(sp)	# check if happened in user mode?
280	jeql	3f			# yes, then shift stack up for trap...
281	movl	12(sp),16(sp)		# sorry, no space for which-buss...
282	movl	8(sp),12(sp)
283	movl	4(sp),8(sp)
284	movl	0(sp),4(sp)
285	movl	$T_BUSERR,0(sp)		# push trap type code and...
286	jbr	alltraps		# ...merge with all other traps
2873:					# kernel mode, check to see if...
288	tstl	nofault			# ...doing peek/poke?
289	jeql	4f			# nofault set? if so, jump to it...
290	movl	nofault,4*4+2*4(sp)	# ...setup for non-local goto
291	clrl	nofault
292	jbr	5f
2934:
294	PUSHR
295	pushab	4*4+REGSPC(sp)		# address of bus error parameters
296	callf	$8,_buserror
297	POPR
2985:
299	REST_FPSTAT
300	movab	8(sp),sp		# remove bus error parameters
301	rei
302
303SCBVEC(powfail):			# We should be on interrupt stack now.
304	SAVEpwfl()			# save machine state
305	moval	_Xdoadump-SYSTEM,_scb+SCB_DOADUMP
306	halt
307
308SCBVEC(stray):
309	incl	_cnt+V_INTR		# add to statistics
310	rei
311
312#include "../net/netisr.h"
313	.globl	_netisr
314SCBVEC(netintr):
315	CHECK_SFE(4)
316	SAVE_FPSTAT(4); PUSHR
317#include "imp.h"
318#if NIMP > 0
319	bbc	$NETISR_IMP,_netisr,1f;
320	andl2	$~(1<<NETISR_IMP),_netisr
321	callf	$4,_impintr;
3221:
323#endif
324#ifdef INET
325	bbc	$NETISR_IP,_netisr,1f
326	andl2	$~(1<<NETISR_IP),_netisr
327	callf	$4,_ipintr
3281:
329#endif
330#ifdef NS
331	bbc	$NETISR_NS,_netisr,1f
332	andl2	$~(1<<NETISR_NS),_netisr
333	callf	$4,_nsintr
3341:
335#endif
336	bbc	$NETISR_RAW,_netisr,1f
337	andl2	$~(1<<NETISR_RAW),_netisr
338	callf	$4,_rawintr
3391:
340	incl	_cnt+V_SOFT
341	POPR; REST_FPSTAT
342	rei
343
344SCBVEC(cnrint):
345	CHECK_SFE(4)
346	SAVE_FPSTAT(4); PUSHR;
347	pushl $CPCONS; callf $8,_cnrint;
348	incl	_intrcnt+I_CNR
349	incl	_cnt+V_INTR
350	POPR; REST_FPSTAT;
351	rei
352SCBVEC(cnxint):
353	CHECK_SFE(4)
354	SAVE_FPSTAT(4); PUSHR;
355	pushl $CPCONS; callf $8,_cnxint;
356	incl	_intrcnt+I_CNX
357	incl	_cnt+V_INTR
358	POPR; REST_FPSTAT;
359	rei
360SCBVEC(rmtrint):
361	CHECK_SFE(4)
362	SAVE_FPSTAT(4); PUSHR;
363	pushl $CPREMOT; callf $8,_cnrint;
364	incl	_intrcnt+I_RMTR
365	incl	_cnt+V_INTR
366	POPR; REST_FPSTAT;
367	rei
368SCBVEC(rmtxint):
369	CHECK_SFE(4)
370	SAVE_FPSTAT(4); PUSHR;
371	pushl $CPREMOT; callf $8,_cnxint;
372	incl	_intrcnt+I_RMTX
373	incl	_cnt+V_INTR
374	POPR; REST_FPSTAT;
375	rei
376
377#define PUSHPCPSL	pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp);
378
379SCBVEC(hardclock):
380	tstl	_clk_enable
381	bneq	1f
382	rei
3831:
384	CHECK_SFE(4)
385	SAVE_FPSTAT(4); PUSHR
386	PUSHPCPSL			# push pc and psl
387	callf	$12,_hardclock		# hardclock(pc,psl)
388	incl	_intrcnt+I_CLOCK
389	incl	_cnt+V_INTR		## temp so not to break vmstat -= HZ
390	POPR; REST_FPSTAT
391	rei
392SCBVEC(softclock):
393	CHECK_SFE(4)
394	SAVE_FPSTAT(4); PUSHR;
395	PUSHPCPSL				# push pc and psl
396	callf	$12,_softclock			# softclock(pc,psl)
397	incl	_cnt+V_SOFT
398	POPR; REST_FPSTAT
399	rei
400
401/*
402 * Stray VERSAbus interrupt catch routines
403 */
404	.data
405#define	PJ	.align 2; callf $4,_Xvstray
406	.globl	_catcher
407_catcher:
408	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
409	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
410	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
411	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
412	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
413	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
414	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
415	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
416	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
417	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
418	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
419	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
420
421	.align	2
422	.globl	_cold
423_cold:	.long	0x3
424
425	.text
426SCBVEC(vstray):
427	.word	0
428	bbc	$0,_cold,2f		# system running?
429	bbc	$1,_cold,1f		# doing autoconfig?
430	jbr	3f			# random interrupt, ignore
4311:
432	mfpr	$IPL,r12		# ...setup br and cvec
433	subl3	$_catcher+7,-8(fp),r11; shar $3,r11,r11
434	addl2	$SCB_DEVBASE,r11
435	jbr	3f
4362:
437	PUSHR
438	subl3	$_catcher+7,-8(fp),r0; shar $3,r0,r0
439	addl3	$SCB_DEVBASE,r0,-(sp);
440	mfpr	$IPL,-(sp)
441	PRINTF(2, "stray intr ipl %x vec %x\n")
442	POPR
4433:	moval	0f,-8(fp); ret		# pop callf frame...
4440:	rei				# ...and return
445
446/*
447 * Trap and fault vector routines
448 */
449#define	TRAP(a)	pushl $T_/**/a; jbr alltraps
450
451/*
452 * Ast delivery (profiling and/or reschedule)
453 */
454
455SCBVEC(kspnotval):
456	CHECK_SFE(4)
457	pushl $0;
458	SAVE_FPSTAT(8)
459	TRAP(KSPNOTVAL)
460SCBVEC(privinflt):
461	CHECK_SFE(4)
462	pushl $0;
463	SAVE_FPSTAT(8)
464	TRAP(PRIVINFLT)
465SCBVEC(resopflt):
466	CHECK_SFE(4)
467	pushl $0;
468	SAVE_FPSTAT(8)
469	TRAP(RESOPFLT)
470SCBVEC(resadflt):
471	CHECK_SFE(4)
472	pushl $0;
473	SAVE_FPSTAT(8)
474	TRAP(RESADFLT)
475SCBVEC(bptflt):
476	CHECK_SFE(4)
477	pushl $0;
478	SAVE_FPSTAT(8)
479	TRAP(BPTFLT)
480SCBVEC(kdbintr):
481	CHECK_SFE(4);
482	pushl $0;
483	SAVE_FPSTAT(8);
484	TRAP(KDBTRAP);
485SCBVEC(tracep):
486	CHECK_SFE(4)
487	pushl $0;
488	SAVE_FPSTAT(8)
489	TRAP(TRCTRAP)
490SCBVEC(alignflt):
491#ifdef ALIGN
492	bitl	$PSL_CURMOD,4(sp)
493	jeql	align_excp		# Can't emulate for kernel mode !
494	jbr	non_aligned		# Only emulated for user mode.
495align_excp:
496#else
497	CHECK_SFE(4)
498#endif
499	pushl $0;
500	SAVE_FPSTAT(8)
501	TRAP(ALIGNFLT)
502SCBVEC(arithtrap):
503	CHECK_SFE(8)
504	SAVE_FPSTAT(8)
505	TRAP(ARITHTRAP)
506
507SCBVEC(protflt):
508	CHECK_SFE(12)
509	bitl	$1,(sp)+
510	jneq	segflt
511	SAVE_FPSTAT(8)
512	TRAP(PROTFLT)
513segflt:
514	SAVE_FPSTAT(8)
515	TRAP(SEGFLT)
516
517SCBVEC(fpm):			# Floating Point Emulation
518#ifdef FPE
519	CHECK_SFE(16)
520	SAVE_FPSTAT(16)
521	incl	_cnt+V_FPE	# count emulation traps
522	callf	$4,_fpemulate
523	REST_FPSTAT
524#endif
525	moval	8(sp),sp	# Pop operand
526	tstl	(sp)		# Stack= PSL, PC, return_code
527	jneq	_Xarithtrap	# If not OK, emulate F.P. exception
528	movab	4(sp),sp	# Else remove return_code and
529	rei
530
531SCBVEC(sfexcep):
532	CHECK_SFE(4)
533	pushl $0
534	SAVE_FPSTAT(8)
535	TRAP(ASTFLT)
536
537SCBVEC(transflt):
538	CHECK_SFE(12)
539	bitl	$2,(sp)+
540	bneq	tableflt
541pageflt:
542	SAVE_FPSTAT(8)
543	TRAP(PAGEFLT)
544tableflt:
545	SAVE_FPSTAT(8)
546	TRAP(TABLEFLT)
547
548#define REST_STACK	movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
549
550alltraps:
551	mfpr	$USP,-(sp);
552	callf	$4,_trap;
553	mtpr	(sp)+,$USP
554	incl	_cnt+V_TRAP
555	REST_STACK			# pop type, code, and fp stuff
556	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
557	rei
558
559SCBVEC(syscall):
560	CHECK_SFE(8)
561	SAVE_FPSTAT(8)
562	pushl	$T_SYSCALL
563	mfpr	$USP,-(sp);
564	callf	$4,_syscall;
565	mtpr	(sp)+,$USP
566	incl	_cnt+V_SYSCALL
567	REST_STACK			# pop type, code, and fp stuff
568	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
569	rei
570
571/*
572 * System page table.
573 *
574 * Mbmap and Usrptmap are enlarged by CLSIZE entries
575 * as they are managed by resource maps starting with index 1 or CLSIZE.
576 */
577#define	vaddr(x)	((((x)-_Sysmap)/4)*NBPG+SYSTEM)
578#define	SYSMAP(mname, vname, npte)			\
579_/**/mname:	.globl	_/**/mname;		\
580	.space	(npte)*4;			\
581	.globl	_/**/vname;			\
582	.set	_/**/vname,vaddr(_/**/mname)
583
584	.data
585	.align	2
586	SYSMAP(Sysmap	,Sysbase	,SYSPTSIZE	)
587	SYSMAP(Forkmap	,forkutl	,UPAGES		)
588	SYSMAP(Xswapmap	,xswaputl	,UPAGES		)
589	SYSMAP(Xswap2map,xswap2utl	,UPAGES		)
590	SYSMAP(Swapmap	,swaputl	,UPAGES		)
591	SYSMAP(Pushmap	,pushutl	,UPAGES		)
592	SYSMAP(Vfmap	,vfutl		,UPAGES		)
593	SYSMAP(CMAP1	,CADDR1		,1		)
594	SYSMAP(CMAP2	,CADDR2		,1		)
595	SYSMAP(mmap	,vmmap		,1		)
596	SYSMAP(alignmap	,alignutl	,1		)	/* XXX */
597	SYSMAP(msgbufmap,msgbuf		,MSGBUFPTECNT	)
598	SYSMAP(Mbmap	,mbutl		,NMBCLUSTERS*CLSIZE+CLSIZE )
599	SYSMAP(kmempt	,kmembase	,1024*CLSIZE 	)
600#ifdef	GPROF
601	SYSMAP(profmap	,profbase	,600*CLSIZE	)
602#endif
603	/*
604	 * Enlarge kmempt as needed for bounce buffers allocated
605	 * by tahoe controllers.
606	 */
607#include "dk.h"
608	SYSMAP(_vdmap	,_vdbase	,NVD*(MAXPHYS/NBPG+CLSIZE) )
609#include "yc.h"
610	SYSMAP(_cymap	,_cybase	,NCY*(MAXPHYS/NBPG+CLSIZE) )
611#include "mp.h"
612	SYSMAP(_mpmap	,_mpbase	,NMP*14		)
613	SYSMAP(ekmempt	,kmemlimit	,0		)
614
615	SYSMAP(VMEMbeg	,vmembeg	,0		)
616	SYSMAP(VMEMmap	,vmem		,VBIOSIZE 	)
617	SYSMAP(VMEMmap1	,vmem1		,0		)
618#include "ace.h"
619	SYSMAP(_acemap1	,_acemem	,NACE*32	)
620	SYSMAP(VMEMend	,vmemend	,0		)
621
622	SYSMAP(VBmap	,vbbase		,CLSIZE		)
623	SYSMAP(_vdbmap	,_vdbbase	,NVD*(MAXPHYS/NBPG+CLSIZE) )
624	SYSMAP(_cybmap	,_cybbase	,NCY*(MAXPHYS/NBPG+CLSIZE) )
625	SYSMAP(_mpbmap	,_mpbbase	,NMP*14		)
626	SYSMAP(eVBmap	,vbend		,0		)
627
628	SYSMAP(Usrptmap	,usrpt		,USRPTSIZE+CLSIZE )
629eSysmap:
630	.globl	_Syssize
631	.set	_Syssize,(eSysmap-_Sysmap)/4
632
633	.text
634/*
635 * Initialization
636 *
637 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
638 */
639	.align	2
640	.globl	start
641start:
642	.word	0
643/* set system control block base and system page table params */
644	mtpr	$_scb-SYSTEM,$SCBB
645	mtpr	$_Sysmap-SYSTEM,$SBR
646	mtpr	$_Syssize,$SLR
647/* double map the kernel into the virtual user addresses of phys mem */
648	mtpr	$_Sysmap,$P0BR
649	mtpr	$_Syssize,$P0LR
650	mtpr	$_Sysmap,$P1BR			# against Murphy
651	mtpr	$_Syssize,$P1LR
652/* set ISP */
653	movl	$_intstack-SYSTEM+NISP*NBPG,sp	# still physical
654	mtpr	$_intstack+NISP*NBPG,$ISP
655/* count up memory */
656	clrl	r7
6571:	pushl	$1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
658	ACBL($MAXMEM*1024-1,$64*1024,r7,1b)
6599:
660/* clear memory from kernel bss and pages for proc 0 u. and page table */
661	movab	_edata,r6; andl2 $~SYSTEM,r6
662	movab	_end,r5; andl2 $~SYSTEM,r5
663#ifdef KDB
664	subl2	$4,r5
6651:	clrl	(r6); ACBL(r5,$4,r6,1b)		# clear just bss
666	addl2	$4,r5
667	bbc	$6,r11,0f			# check RB_KDB
668	andl3	$~SYSTEM,r9,r5			# skip symbol & string tables
669	andl3	$~SYSTEM,r9,r6
670#endif
6710:	orl3	$SYSTEM,r5,r9			# convert to virtual address
672	addl2	$NBPG-1,r9			# roundup to next page
673	addl2	$(UPAGES*NBPG)+NBPG+NBPG,r5
6741:	clrl	(r6); ACBL(r5,$4,r6,1b)
675/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */
676	orw2	$0x01fff,_trap
677	orw2	$0x01fff,_syscall
678#ifdef FPE
679	orw2	$0x01fff,_fpemulate
680#endif
681	orw2	$0x01ffc,_panic			# for debugging (no r0|r1)
682	callf	$4,_fixctlrmask			# setup for autoconfig
683/* initialize system page table: scb and int stack writeable */
684	clrl	r2
685	movab	eintstack,r1
686	andl2	$~SYSTEM,r1
687	shrl 	$PGSHIFT,r1,r1			# r1-page number of eintstack
688/* make 1st page processor storage read/only, 2nd read/write */
689	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
690	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]; incl r2;
691/* other parts of the system are read/write for kernel */
6921:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2];	# data:kernel write+phys=virtual
693	aoblss r1,r2,1b
694/* make rsstk read-only as red zone for interrupt stack */
695	andl2	$~PG_PROT,_rsstkmap
696	orl2	$PG_V|PG_KR,_rsstkmap
697/* make kernel text space read-only */
698	movab	_etext+NBPG-1,r1
699	andl2	$~SYSTEM,r1
700	shrl 	$PGSHIFT,r1,r1
7011:	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]
702	aoblss r1,r2,1b
703/* make kernel data, bss, read-write */
704	andl3	$~SYSTEM,r9,r1
705	shrl 	$PGSHIFT,r1,r1
7061:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]
707	aoblss r1,r2,1b
708/* go to mapped mode, have to change both pc and sp to system addresses */
709	mtpr	$1,$TBIA
710	mtpr	$1,$PADC			# needed by HW parity&ECC logic
711	mtpr	$1,$PACC			# just in case
712	mtpr 	$1,$MME
713	movab	SYSTEM(sp),sp
714	jmp 	*$0f
7150:
716/* disable any interrupts */
717	movl	$0,_intenable
718/* init mem sizes */
719	shrl	$PGSHIFT,r7,_maxmem
720	movl	_maxmem,_physmem
721	movl	_maxmem,_freemem
722/* setup context for proc[0] == scheduler */
723	andl3	$~SYSTEM,r9,r6			# convert to physical
724	andl2	$~(NBPG-1),r6			# make page boundary
725/* setup page table for proc[0] */
726	shrl	$PGSHIFT,r6,r3			# r3 = btoc(r6)
727	orl3	$PG_V|PG_KW,r3,_Usrptmap	# init first upt entry
728	incl	r3				# r3 - next page
729	movab	_usrpt,r0			# r0 - first user page
730	mtpr	r0,$TBIS
731/* init p0br, p0lr */
732	mtpr	r0,$P0BR			# no p0 for proc[0]
733	mtpr	$0,$P0LR
734	mtpr	r0,$P1BR			# no p1 either
735	mtpr	$0,$P1LR
736/* init p2br, p2lr */
737	movab	NBPG(r0),r0
738	movl	$PPAGES-UPAGES,r1
739	mtpr	r1,$P2LR
740	moval	-4*PPAGES(r0),r2
741	mtpr	r2,$P2BR
742/* setup mapping for UPAGES of _u */
743	clrl	r2
744	movl 	$SYSTEM,r1
745	addl2 	$UPAGES,r3
746	jbr 2f
7471:	decl	r3
748	moval	-NBPG(r1),r1	# r1 = virtual add of next (downward) _u page
749	subl2	$4,r0		# r0 = pte address
750	orl3	$PG_V|PG_URKW,r3,(r0)
751	mtpr	r1,$TBIS
7522:	aobleq	$UPAGES,r2,1b
753/* initialize (slightly) the pcb */
754	movab	UPAGES*NBPG(r1),PCB_KSP(r1)	# KSP starts at end of _u
755	movl	r1,PCB_USP(r1)			# USP starts just below _u
756	mfpr	$P0BR,PCB_P0BR(r1)
757	mfpr	$P0LR,PCB_P0LR(r1)
758	mfpr	$P1BR,PCB_P1BR(r1)
759	mfpr	$P1LR,PCB_P1LR(r1)
760	mfpr	$P2BR,PCB_P2BR(r1)
761	mfpr	$P2LR,PCB_P2LR(r1)
762	movl	$CLSIZE,PCB_SZPT(r1)		# init u.u_pcb.pcb_szpt
763	movl	r9,PCB_R9(r1)			# r9 obtained from boot
764	movl	r10,PCB_R10(r1)			# r10 obtained from boot
765	movl	r11,PCB_R11(r1)			# r11 obtained from CP on boot
766	movab	1f,PCB_PC(r1)			# initial pc
767	clrl	PCB_PSL(r1)			# kernel mode, ipl=0
768	shll	$PGSHIFT,r3,r3
769	mtpr	r3,$PCBB			# first pcbb (physical)
770/* go to kernel mode */
771	ldpctx
772	rei					# Actually next instruction:
773/* put signal trampoline code in u. area */
7741:	movab	sigcode,r0
775	movab	_u+PCB_SIGC,r1
776	movl	$19,r2
777	movblk
778/* save boot device in global _bootdev */
779	movl	r10,_bootdev
780/* save reboot flags in global _boothowto */
781	movl	r11,_boothowto
782/* save end of symbol & string table in global _bootesym */
783	subl3	$NBPG-1,r9,_bootesym
784/* calculate firstaddr, and call main() */
785	andl3	$~SYSTEM,r9,r0
786	shrl	$PGSHIFT,r0,-(sp)
787	addl2	$UPAGES+1,(sp)			# first physical unused page
788	callf 	$8,_main
789/* proc[1] == /etc/init now running here in kernel mode; run icode */
790	pushl	$PSL_CURMOD			# User mode PSL
791	pushl $0				# PC = 0 (virtual now)
792	rei
793
794/*
795 * Mask for saving/restoring registers on entry to
796 * a user signal handler.  Space for the registers
797 * is reserved in sendsig, so beware if you want
798 * to change the mask.
799 */
800#define	SIGREGS	(R0|R1|R2|R3|R4|R5)
801	.align	2
802	.globl	sigcode
803sigcode:
804	storer	$SIGREGS,16(sp)	# save volatile registers
805	calls	$4*3+4,*12(sp)	# params pushed by sendsig for handler
806	loadr	$SIGREGS,4(sp)	# restore volatile registers
807	movab	24(sp),fp	# use parameter list set up in sendsig
808	kcall	$SYS_sigreturn	# cleanup mask and onsigstack
809	halt			# sigreturn does not return!
810
811	.globl	_icode
812	.globl	_initflags
813	.globl	_szicode
814/*
815 * Icode is copied out to process 1 to exec /etc/init.
816 * If the exec fails, process 1 exits.
817 */
818	.align	2
819_icode:
820	pushab	b`argv-l0(pc)
821l0:	pushab	b`init-l1(pc)
822l1:	pushl	$2
823	movab	(sp),fp
824	kcall	$SYS_execv
825	pushl	r0
826	kcall	$SYS_exit
827
828init:	.asciz	"/etc/init"
829	.align	2
830_initflags:
831	.long	0
832argv:	.long	init+5-_icode
833	.long	_initflags-_icode
834	.long	0
835_szicode:
836	.long	_szicode-_icode
837
838/*
839 * Primitives
840 */
841
842/*
843 * badaddr(addr, len)
844 *	see if access addr with a len type instruction causes a machine check
845 *	len is length of access (1=byte, 2=short, 4=long)
846 *	r0 = 0 means good(exists); r0 =1 means does not exist.
847 */
848ENTRY(badaddr, R3|R4)
849	mfpr	$IPL,r1
850	mtpr	$HIGH,$IPL
851	movl	_scb+SCB_BUSERR,r2
852	movl	4(fp),r3
853	movl	8(fp),r4
854	movab	9f,_scb+SCB_BUSERR
855	bbc	$0,r4,1f; tstb	(r3)
8561:	bbc	$1,r4,1f; tstw	(r3)
8571:	bbc	$2,r4,1f; tstl	(r3)
8581:	clrl	r0
8592:	movl	r2,_scb+SCB_BUSERR
860	mtpr	r1,$IPL
861	ret
862
863	.align	2
8649:				# catch buss error (if it comes)
865	andl3	4(sp),$ERRCD,r0
866	cmpl	r0,$APE
867	jneq	1f
868	halt			# address parity error
8691:	cmpl	r0,$VBE
870	jneq	1f
871	halt			# Versabus error
8721:
873	movl	$1,r0		# Anything else = bad address
874	movab	8(sp),sp	# discard buss error trash
875	movab	2b,(sp)		# new program counter on stack.
876	rei
877
878/*
879 * badcyaddr(addr)
880 *	see if access tape master controller addr causes a bus error
881 *	r0 = 0: no error; r0 = 1: timeout error.
882 */
883ENTRY(badcyaddr, 0)
884	mfpr	$IPL,r1
885	mtpr	$HIGH,$IPL
886	clrl	r2
887	movab	2f,nofault
888	movob	$-1, *4(fp)
8891:	aobleq	$1000, r2, 1b
890	clrl	nofault			# made it w/o bus error
891	clrl	r0
892	jbr	3f
8932:	movl	$1,r0
8943:	mtpr	r1,$IPL
895	ret
896
897/*
898 * peek(addr)
899 *	fetch word and catch any bus error
900 */
901ENTRY(peek, 0)
902	mfpr	$IPL,r1
903	mtpr	$0x18,$IPL	# not reentrant
904	movl	4(fp),r2
905	movab	1f,nofault
906	movw	(r2),r0
907	clrl	nofault
908	andl2	$0xffff,r0
909	jbr	2f
9101:	movl	$-1,r0		# bus error
9112:	mtpr	r1,$IPL
912	ret
913
914/*
915 * poke(addr, val)
916 *	write word and catch any bus error
917 */
918ENTRY(poke, R3)
919	mfpr	$IPL,r1
920	mtpr	$0x18,$IPL	# not reentrant
921	movl	4(fp),r2
922	movl	8(fp),r3
923	clrl	r0
924	movab	1f,nofault
925	movw	r3,(r2)
926	clrl	nofault
927	jbr	2f
9281:	movl	$-1,r0		# bus error
9292:	mtpr	r1,$IPL
930	ret
931
932/*
933 * Copy a potentially overlapping block of memory.
934 *
935 * ovbcopy(src, dst, count)
936 *	caddr_t src, dst; unsigned count;
937 */
938ENTRY(ovbcopy, R3|R4)
939	movl	4(fp),r0
940	movl	8(fp),r1
941	movl	12(fp),r2
942	cmpl	r0,r1
943	bgtru	1f			# normal forward case
944	beql	2f			# equal, nothing to do
945	addl2	r2,r0			# may be overlapping
946	cmpl	r0,r1
947	bgtru	3f
948	subl2	r2,r0			# normal forward case
9491:
950	movblk
9512:
952	ret
9533:
954	addl2	r2,r1			# overlapping, must do backwards
955	subl3	r0,r1,r3
956	movl	r2,r4
957	jbr	5f
9584:
959	subl2	r3,r0
960	subl2	r3,r1
961	movl	r3,r2
962	movblk
963	subl2	r3,r0
964	subl2	r3,r1
965	subl2	r3,r4
9665:
967	cmpl	r4,r3
968	jgtr	4b
969	movl	r4,r2
970	subl2	r2,r0
971	subl2	r2,r1
972	movblk
973	ret
974
975/*
976 * Copy a null terminated string from the user address space into
977 * the kernel address space.
978 *
979 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
980 */
981ENTRY(copyinstr, 0)
982	movl	12(fp),r5		# r5 = max length
983	jlss	5f
984	movl	8(fp),r4		# r4 = kernel address
985	movl	4(fp),r0		# r0 = user address
986	andl3	$(NBPG*CLSIZE-1),r0,r2	# r2 = bytes on first page
987	subl3	r2,$(NBPG*CLSIZE),r2
9881:
989	cmpl	r5,r2			# r2 = min(bytes on page, length left);
990	jgeq	2f
991	movl	r5,r2
9922:
993	prober	$1,(r0),r2		# bytes accessible?
994	jeql	5f
995	subl2	r2,r5			# update bytes left count
996	movl	r2,r3			# r3 = saved count
997	movl	r0,r1
998	cmps3				# check for null
999	tstl	r2
1000	jneq	3f
1001	subl2	r3,r0			# back up r0
1002	movl	r4,r1
1003	movl	r3,r2
1004	movblk				# copy in next piece
1005	movl	r1,r4
1006	movl	$(NBPG*CLSIZE),r2	# check next page
1007	tstl	r5			# run out of space?
1008	jneq	1b
1009	movl	$ENOENT,r0		# set error code and return
1010	jbr	6f
10113:
1012	tstl	16(fp)			# return length?
1013	beql	4f
1014	subl3	r5,12(fp),r5		# actual len = maxlen - unused pages
1015	subl2	r2,r5			#	- unused on this page
1016	addl3	$1,r5,*16(fp)		#	+ the null byte
10174:
1018	movl	r4,r1
1019	subl3	r2,r3,r2		# calc char cnt
1020	subl2	r2,r0			# back up r0
1021	incl	r2			# add on null byte
1022	movblk				# copy last piece
1023	clrl	r0
1024	ret
10255:
1026	movl	$EFAULT,r0
10276:
1028	tstl	16(fp)
1029	beql	7f
1030	subl3	r5,12(fp),*16(fp)
10317:
1032	ret
1033
1034/*
1035 * Copy a null terminated string from the kernel
1036 * address space to the user address space.
1037 *
1038 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1039 */
1040ENTRY(copyoutstr, 0)
1041	movl	12(fp),r5		# r5 = max length
1042	jlss	5f
1043	movl	4(fp),r0		# r0 = kernel address
1044	movl	8(fp),r4		# r4 = user address
1045	andl3	$(NBPG*CLSIZE-1),r4,r2	# r2 = bytes on first page
1046	subl3	r2,$(NBPG*CLSIZE),r2
10471:
1048	cmpl	r5,r2			# r2 = min(bytes on page, length left);
1049	jgeq	2f
1050	movl	r5,r2
10512:
1052	probew	$1,(r4),r2		# bytes accessible?
1053	jeql	5f
1054	subl2	r2,r5			# update bytes left count
1055	movl	r2,r3			# r3 = saved count
1056	movl	r0,r1
1057/*
1058 * This is a workaround for a microcode bug that causes
1059 * a trap type 9 when cmps3/movs3 touches the last byte
1060 * on a valid page immediately followed by an invalid page.
1061 */
1062#ifdef good_cmps3
1063	cmps3				# check for null
1064	tstl	r2
1065	jneq	3b
1066#else
1067	decl	r2
1068	beql	9f			# cannot handle case of r2 == 0!
1069	cmps3				# check for null up to last byte
10709:
1071	incl	r2
1072	cmpl	$1,r2			# get to last byte on page?
1073	bneq	3b
1074	tstb	(r0)			# last byte on page null?
1075	beql	3b
1076	incl	r0			# not null, so bump pointer
1077#endif not good_cmps3
1078	subl2	r3,r0			# back up r0
1079	movl	r4,r1
1080	movl	r3,r2
1081	movblk				# copy out next piece
1082	movl	r1,r4
1083	movl	$(NBPG*CLSIZE),r2	# check next page
1084	tstl	r5			# run out of space?
1085	jneq	1b
1086	movl	$ENOENT,r0		# set error code and return
1087	jbr	6b
10885:
1089	clrl	*$0		# this should never execute, if it does
1090	movl	$EFAULT,r0	#  save me a core dump (mkm - 9/87)
10916:
1092	tstl	16(fp)
1093	beql	7f
1094	subl3	r5,12(fp),*16(fp)
10957:
1096	ret
1097
1098
1099/*
1100 * Copy a null terminated string from one point to another in
1101 * the kernel address space.
1102 *
1103 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1104 */
1105ENTRY(copystr, 0)
1106	movl	12(fp),r3		# r3 = max length
1107	jlss	5b
1108	movl	4(fp),r0		# r0 = src address
1109	movl	8(fp),r4		# r4 = dest address
1110	clrl	r5			# r5 = bytes left
1111	movl	r3,r2			# r2 = max bytes to copy
1112	movl	r0,r1
1113	cmps3				# check for null
1114	tstl	r2
1115	jneq	3b
1116	subl2	r3,r0			# back up r0
1117	movl	r4,r1
1118	movl	r3,r2
1119	movblk				# copy next piece
1120	movl	$ENOENT,r0		# set error code and return
1121	jbr	6b
1122
1123/*
1124 * Copy a block of data from the user address space into
1125 * the kernel address space.
1126 *
1127 * copyin(fromaddr, toaddr, count)
1128 */
1129ENTRY(copyin, 0)
1130	movl	12(fp),r0		# copy length
1131	blss	9f
1132	movl	4(fp),r1		# copy user address
1133	cmpl	$(CLSIZE*NBPG),r0	# probing one page or less ?
1134	bgeq	2f			# yes
11351:
1136	prober	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible ?
1137	beql	9f			# no
1138	addl2	$(CLSIZE*NBPG),r1	# incr user address ptr
1139	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
11402:
1141	prober	$1,(r1),r0		# bytes accessible ?
1142	beql	9f			# no
1143	MOVC3(4(fp),8(fp),12(fp))
1144	clrl	r0
1145	ret
11469:
1147	movl	$EFAULT,r0
1148	ret
1149
1150/*
1151 * Copy a block of data from the kernel
1152 * address space to the user address space.
1153 *
1154 * copyout(fromaddr, toaddr, count)
1155 */
1156ENTRY(copyout, 0)
1157	movl	12(fp),r0		# get count
1158	blss	9b
1159	movl	8(fp),r1		# get user address
1160	cmpl	$(CLSIZE*NBPG),r0	# can do in one probew?
1161	bgeq	2f			# yes
11621:
1163	probew	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible?
1164	beql	9b			# no
1165	addl2	$(CLSIZE*NBPG),r1	# increment user address
1166	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
11672:
1168	probew	$1,(r1),r0		# bytes accessible?
1169	beql	9b			# no
1170	MOVC3(4(fp),8(fp),12(fp))
1171	clrl	r0
1172	ret
1173
1174/*
1175 * non-local goto's
1176 */
1177#ifdef notdef
1178ENTRY(setjmp, 0)
1179	movl	4(fp),r0
1180	movl	(fp),(r0); addl2 $4,r0		# save fp
1181	movl	-8(fp),(r0)			# save pc
1182	clrl	r0
1183	ret
1184#endif
1185
1186ENTRY(longjmp, 0)
1187	movl	4(fp),r0
1188	movl	(r0),newfp; addl2 $4,r0		# must save parameters in memory
1189	movl	(r0),newpc			# as all regs may be clobbered.
11901:
1191	cmpl	fp,newfp			# are we there yet?
1192	bgequ	2f				# yes
1193	moval	1b,-8(fp)			# redirect return pc to us!
1194	ret					# pop next frame
11952:
1196	beql	3f				# did we miss our frame?
1197	pushab	4f				# yep ?!?
1198	callf	$8,_panic
11993:
1200	movl	newpc,r0			# all done, just return
1201	jmp	(r0)				# to setjmp `ret'
1202
1203	.data
1204newpc:	.space	4
1205newfp:	.space	4
12064:	.asciz	"longjmp"
1207	.text
1208
1209/*
1210 * setjmp that saves all registers as the call frame may not
1211 * be available to recover them in the usual manner by longjmp.
1212 * Called before swapping out the u. area, restored by resume()
1213 * below.
1214 */
1215ENTRY(savectx, 0)
1216	movl	4(fp),r2
1217	storer	$0x1ff8,(r2); addl2 $40,r2	# r3-r12
1218	movl	(fp),(r2); addl2 $4,r2		# fp
1219	movab	8(fp),(r2); addl2 $4,r2		# sp
1220	movl	-8(fp),(r2)			# pc
1221	clrl	r0
1222	ret
1223
1224#ifdef KDB
1225/*
1226 * C library -- reset, setexit
1227 *
1228 *	reset(x)
1229 * will generate a "return" from
1230 * the last call to
1231 *	setexit()
1232 * by restoring r2 - r12, fp
1233 * and doing a return.
1234 * The returned value is x; on the original
1235 * call the returned value is 0.
1236 */
1237ENTRY(setexit, 0)
1238	movab	setsav,r0
1239	storer	$0x1ffc, (r0)
1240	movl	(fp),44(r0)		# fp
1241	moval	4(fp),48(r0)		# sp
1242	movl	-8(fp),52(r0)		# pc
1243	clrl	r0
1244	ret
1245
1246ENTRY(reset, 0)
1247	movl	4(fp),r0	# returned value
1248	movab	setsav,r1
1249	loadr	$0x1ffc,(r1)
1250	movl	44(r1),fp
1251	movl	48(r1),sp
1252	jmp 	*52(r1)
1253
1254	.data
1255	.align	2
1256setsav:	.space	14*4
1257	.text
1258#endif
1259
1260	.globl	_whichqs
1261	.globl	_qs
1262	.globl	_cnt
1263
1264	.globl	_noproc
1265	.comm	_noproc,4
1266	.globl	_runrun
1267	.comm	_runrun,4
1268/*
1269 * The following primitives use the fancy TAHOE instructions.
1270 * _whichqs tells which of the 32 queues _qs
1271 * have processes in them.  setrq puts processes into queues, remrq
1272 * removes them from queues.  The running process is on no queue,
1273 * other processes are on a queue related to p->p_pri, divided by 4
1274 * actually to shrink the 0-127 range of priorities into the 32 available
1275 * queues.
1276 */
1277
1278/*
1279 * setrq(p), using fancy TAHOE instructions.
1280 *
1281 * Call should be made at spl8(), and p->p_stat should be SRUN
1282 */
1283ENTRY(setrq, 0)
1284	movl	4(fp),r0
1285	tstl	P_RLINK(r0)		## firewall: p->p_rlink must be 0
1286	beql	set1			##
1287	pushab	set3			##
1288	callf	$8,_panic		##
1289set1:
1290	movzbl	P_PRI(r0),r1		# put on queue which is p->p_pri / 4
1291	shar	$2,r1,r1
1292	shal	$1,r1,r2
1293	moval	_qs[r2],r2
1294	insque	(r0),*4(r2)		# at end of queue
1295	shal	r1,$1,r1
1296	orl2	r1,_whichqs		# mark queue non-empty
1297	ret
1298
1299set3:	.asciz	"setrq"
1300
1301/*
1302 * remrq(p), using fancy TAHOE instructions
1303 *
1304 * Call should be made at spl8().
1305 */
1306ENTRY(remrq, 0)
1307	movl	4(fp),r0
1308	movzbl	P_PRI(r0),r1
1309	shar	$2,r1,r1
1310	bbs	r1,_whichqs,rem1
1311	pushab	rem3			# it wasn't recorded to be on its q
1312	callf	$8,_panic
1313rem1:
1314	remque	(r0)
1315	bneq	rem2			# q not empty yet
1316	shal	r1,$1,r1
1317	mcoml	r1,r1
1318	andl2	r1,_whichqs		# mark queue empty
1319rem2:
1320	clrl	P_RLINK(r0)		## for firewall checking
1321	ret
1322
1323rem3:	.asciz	"remrq"
1324
1325/*
1326 * Masterpaddr is the p->p_addr of the running process on the master
1327 * processor.  When a multiprocessor system, the slave processors will have
1328 * an array of slavepaddr's.
1329 */
1330	.globl	_masterpaddr
1331	.data
1332	.align	2
1333_masterpaddr: .long	0
1334
1335	.text
1336sw0:	.asciz	"swtch"
1337
1338/*
1339 * When no processes are on the runq, swtch branches to idle
1340 * to wait for something to come ready.
1341 */
1342	.globl  Idle
1343Idle: idle:
1344	movl	$1,_noproc
1345	mtpr	$0,$IPL			# must allow interrupts here
13461:
1347	tstl	_whichqs		# look for non-empty queue
1348	bneq	sw1
1349	brb	1b
1350
1351badsw:	pushab	sw0
1352	callf	$8,_panic
1353	/* NOTREACHED */
1354
1355	.align	2
1356/*
1357 * swtch(), using fancy tahoe instructions
1358 */
1359ENTRY(swtch, 0)
1360	movl	(fp),fp			# prepare for rei
1361	movl	(sp),4(sp)		# saved pc
1362	tstl	(sp)+
1363	movpsl	4(sp)
1364	incl	_cnt+V_SWTCH
1365sw1:	ffs	_whichqs,r0		# look for non-empty queue
1366	blss	idle			# if none, idle
1367	mtpr	$0x18,$IPL		# lock out all so _whichqs==_qs
1368	bbc	r0,_whichqs,sw1		# proc moved via interrupt
1369	shal	$1,r0,r1
1370	moval	_qs[r1],r1
1371	movl	(r1),r2			# r2 = p = highest pri process
1372	remque	*(r1)
1373	bvs	badsw			# make sure something was there
1374	bneq	sw2
1375	shal	r0,$1,r1
1376	mcoml	r1,r1
1377	andl2	r1,_whichqs		# no more procs in this queue
1378sw2:
1379	clrl	_noproc
1380	clrl	_runrun
1381#ifdef notdef
1382	tstl	P_WCHAN(r2)		## firewalls
1383	bneq	badsw			##
1384	cmpb	P_STAT(r2),$SRUN	##
1385	bneq	badsw			##
1386#endif
1387	clrl	P_RLINK(r2)		##
1388	movl	*P_ADDR(r2),r0
1389#ifdef notdef
1390	cmpl	r0,_masterpaddr		# resume of current proc is easy
1391	beql	res0
1392#endif
1393	movl	r0,_masterpaddr
1394	shal	$PGSHIFT,r0,r0		# r0 = pcbb(p)
1395	brb	swresume
1396
1397/*
1398 * resume(pf)
1399 */
1400ENTRY(resume, 0)
1401	shal	$PGSHIFT,4(fp),r0	# r0 = pcbb(pf)
1402	movl	(fp),fp			# prepare for rei
1403	movl	(sp)+,4(sp)		# saved pc
1404	tstl	(sp)+
1405	movpsl	4(sp)
1406swresume:
1407	mtpr	$0x18,$IPL		# no interrupts, please
1408	movl	_CMAP2,_u+PCB_CMAP2	# yech
1409	REST_ACC			# restore original accumulator
1410	svpctx
1411	mtpr	r0,$PCBB
1412	ldpctx
1413	movl	_u+PCB_CMAP2,_CMAP2	# yech
1414	mtpr	$_CADDR2,$TBIS
1415res0:
1416	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1417	tstl	P_CKEY(r2)		# does proc have code key?
1418	bneq	1f
1419	callf	$4,_getcodekey		# no, give him one
1420	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1421	movl	r0,P_CKEY(r2)
14221:
1423	tstl	P_DKEY(r2)		# does proc have data key?
1424	bneq	1f
1425	callf	$4,_getdatakey		# no, give him one
1426	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1427	movl	r0,P_DKEY(r2)
14281:
1429	mtpr	P_CKEY(r2),$CCK		# set code cache key
1430	mtpr	P_DKEY(r2),$DCK		# set data cache key
1431	tstl	_u+PCB_SSWAP
1432	bneq	res1
1433	rei
1434res1:					# longjmp to saved context
1435	movl	_u+PCB_SSWAP,r2
1436	clrl	_u+PCB_SSWAP
1437	loadr	$0x3ff8,(r2); addl2 $44,r2	# restore r3-r13 (r13=fp)
1438	movl	(r2),r1; addl2 $4,r2	# fetch previous sp ...
1439	movab	(sp),r0			# ... and current sp and
1440	cmpl	r1,r0			# check for credibility,
1441	bgequ	1f			# if further up stack ...
1442	pushab 2f; callf $8,_panic	# ... panic
1443	/*NOTREACHED*/
14441:					# sp ok, complete return
1445	movl	r1,sp			# restore sp
1446	pushl	$PSL_PRVMOD		# kernel mode, ipl 0
1447	pushl	(r2)			# return address
1448	rei
14492:	.asciz	"ldctx"
1450
1451/*
1452 * {fu,su},{byte,word}
1453 */
1454ENTRY(fuword, 0)
1455	movl	4(fp), r1
1456	prober	$1,(r1),$4		# check access
1457	beql	fserr			# page unreadable
1458	bitl	$1,r1			# check byte alignment
1459	bneq	2f			# odd, do byte-word-byte
1460	bitl	$2,r1			# check word alignment
1461	bneq	1f			# odd, do in 2 words
1462	movl	(r1),r0			# move longword
1463	ret
14641:
1465	movw	(r1),r0			# move two words
1466	shal	$16,r0,r0
1467	movzwl	2(r1),r1		# orw2 sign extends
1468	orl2	r1,r0
1469	ret
14702:
1471	movb	(r1),r0			# move byte-word-byte
1472	shal	$24,r0,r0
1473	movzwl	1(r1),r2		# orw2 sign extends
1474	shal	$8,r2,r2
1475	movzbl	3(r1),r1		# orb2 sign extends
1476	orl2	r2,r1
1477	orl2	r1,r0
1478	ret
1479fserr:
1480	mnegl	$1,r0
1481	ret
1482
1483ENTRY(fubyte, 0)
1484	prober	$1,*4(fp),$1
1485	beql	fserr
1486	movzbl	*4(fp),r0
1487	ret
1488
1489ENTRY(suword, 0)
1490	movl	4(fp), r0
1491	probew	$1,(r0),$4		# check access
1492	beql	fserr			# page unwritable
1493	bitl	$1,r0			# check byte alignment
1494	bneq	1f			# odd byte boundary
1495	bitl	$2,r0			# check word alignment
1496	beql	2f			# longword aligned
1497	movw	8(fp),(r0)		# move two words
1498	movw	10(fp),2(r0)
1499	jbr	3f
15001:
1501	movb	8(fp),(r0)
1502	movb	9(fp),1(r0)
1503	movb	10(fp),2(r0)
1504	movb	11(fp),3(r0)
1505	jbr	3f
15062:
1507	movl	8(fp),(r0)
15083:
1509	clrl	r0
1510	ret
1511
1512ENTRY(subyte, 0)
1513	probew	$1,*4(fp),$1
1514	beql	fserr
1515	movb	11(fp),*4(fp)
1516	clrl	r0
1517	ret
1518
1519/*
1520 * Copy 1 relocation unit (NBPG bytes)
1521 * from user virtual address to physical address
1522 */
1523ENTRY(copyseg, 0)
1524	orl3	$PG_V|PG_KW,8(fp),_CMAP2
1525	mtpr	$_CADDR2,$TBIS	# invalidate entry for copy
1526	MOVC3(4(fp),$_CADDR2,$NBPG)
1527	ret
1528
1529/*
1530 * Clear a page of memory.  The page frame is specified.
1531 *
1532 * clearseg(pf);
1533 */
1534ENTRY(clearseg, 0)
1535	orl3	$PG_V|PG_KW,4(fp),_CMAP1	# Maps to virtual addr CADDR1
1536	mtpr	$_CADDR1,$TBIS
1537	movl	$255,r0				# r0 = limit
1538	clrl	r1				# r1 = index of cleared long
15391:
1540	clrl	_CADDR1[r1]
1541	aobleq	r0,r1,1b
1542	ret
1543
1544/*
1545 * Check user mode read/write access.
1546 *
1547 * useracc(addr, count, mode)
1548 *	caddr_t addr; int count, mode;
1549 * mode = 0	write access
1550 * mode = 1	read access
1551 */
1552ENTRY(useracc, 0)
1553	movl	$1,r2			# r2 = 'user mode' for probew/probew
1554probes:
1555	movl	4(fp),r0		# get va
1556	movl	8(fp),r1		# count
1557	tstl	12(fp)			# test for read access ?
1558	bneq	userar			# yes
1559	cmpl	$(CLSIZE*NBPG),r1	# can we do it in one probe ?
1560	bgeq	uaw2			# yes
1561uaw1:
1562	probew	r2,(r0),$(CLSIZE*NBPG)
1563	beql	uaerr			# no access
1564	addl2	$(CLSIZE*NBPG),r0
1565	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1)
1566uaw2:
1567	probew	r2,(r0),r1
1568	beql	uaerr
1569	movl	$1,r0
1570	ret
1571userar:
1572	cmpl	$(CLSIZE*NBPG),r1
1573	bgeq	uar2
1574uar1:
1575	prober	r2,(r0),$(CLSIZE*NBPG)
1576	beql	uaerr
1577	addl2	$(CLSIZE*NBPG),r0
1578	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1)
1579uar2:
1580	prober	r2,(r0),r1
1581	beql	uaerr
1582	movl	$1,r0
1583	ret
1584uaerr:
1585	clrl	r0
1586	ret
1587
1588/*
1589 * Check kernel mode read/write access.
1590 *
1591 * kernacc(addr, count, mode)
1592 *	caddr_t addr; int count, mode;
1593 * mode = 0	write access
1594 * mode = 1	read access
1595 */
1596ENTRY(kernacc, 0)
1597	clrl	r2		# r2 = 0 means kernel mode probe.
1598	jbr	probes		# Dijkstra would get gastric distress here.
1599
1600/*
1601 * addupc - increment some histogram counter
1602 *	in the profiling buffer
1603 *
1604 * addupc(pc, prof, delta)
1605 *	long pc; short delta; struct uprof *prof;
1606 *
1607 * struct uprof {		# profile arguments
1608 * 	short	*r_base;	# buffer base
1609 * 	unsigned pr_size;	# buffer size
1610 * 	unsigned pr_off;	# pc offset
1611 * 	unsigned pr_scale;	# pc scaling
1612 * }
1613 */
1614ENTRY(addupc, 0)
1615	movl	8(fp),r2		# r2 points to structure
1616	subl3	8(r2),4(fp),r0		# r0 = PC - lowpc
1617	jlss	9f			# PC < lowpc , out of range !
1618	shrl	$1,r0,r0		# the unit is words
1619	shrl	$1,12(r2),r1		# ditto for scale
1620	emul	r1,r0,$0,r0
1621	shrq	$14,r0,r0
1622	tstl	r0			# too big
1623	jneq	9f
1624	cmpl	r1,4(r2)		# Check buffer overflow
1625	jgequ	9f
1626	probew	$1,*0(r2)[r1],$2	# counter accessible?
1627	jeql	9f
1628	shrl	$1,r1,r1		# make r1 word index
1629	addw2	14(fp),*0(r2)[r1]
16309:	ret
1631
1632/*
1633 * scanc(size, cp, table, mask)
1634 */
1635ENTRY(scanc, R3|R4)
1636	movl	8(fp),r0		# r0 = cp
1637	addl3	4(fp),r0,r2		# end = &cp[size]
1638	movl	12(fp),r1		# r1 = table
1639	movb	19(fp),r4		# r4 = mask
1640	decl	r0			# --cp
1641	jbr	0f			# just like Fortran...
16421:					# do {
1643	movzbl	(r0),r3
1644	bitb	r4,(r1)[r3]		#	if (table[*cp] & mask)
1645	jneq	2f			#		break;
16460:	aoblss	r2,r0,1b		# } while (++cp < end);
16472:
1648	subl3	r0,r2,r0; ret		# return (end - cp);
1649
1650/*
1651 * skpc(mask, size, cp)
1652 */
1653ENTRY(skpc, 0)
1654	movl	12(fp),r0		# r0 = cp
1655	addl3	8(fp),r0,r1		# r1 = end = &cp[size];
1656	movb	7(fp),r2		# r2 = mask
1657	decl	r0			# --cp;
1658	jbr	0f
16591:					# do
1660	cmpb	(r0),r2			#	if (*cp != mask)
1661	jneq	2f			#		break;
16620:	aoblss	r1,r0,1b		# while (++cp < end);
16632:
1664	subl3	r0,r1,r0; ret		# return (end - cp);
1665
1666/*
1667 * locc(mask, size, cp)
1668 */
1669ENTRY(locc, 0)
1670	movl	12(fp),r0		# r0 = cp
1671	addl3	8(fp),r0,r1		# r1 = end = &cp[size]
1672	movb	7(fp),r2		# r2 = mask
1673	decl	r0			# --cp;
1674	jbr	0f
16751:					# do
1676	cmpb	(r0),r2			#	if (*cp == mask)
1677	jeql	2f			#		break;
16780:	aoblss	r1,r0,1b		# while (++cp < end);
16792:
1680	subl3	r0,r1,r0; ret		# return (end - cp);
1681
1682#ifdef ALIGN
1683#include "../tahoealign/align.h"
1684
1685	.globl	_alignment
1686/*
1687 * There's an intimate relationship between this piece of code
1688 * and the alignment emulation code (especially the layout
1689 * of local variables in alignment.c! Don't change unless
1690 * you update both this, alignment.h and alignment.c !!
1691 */
1692non_aligned:
1693	orb2	$EMULATEALIGN,_u+U_EOSYS
1694	incl	_cnt+V_TRAP
1695	incl	_cnt+V_ALIGN		# count emulated alignment traps
1696	moval	4(sp),_user_psl
1697	SAVE_FPSTAT(4)			# Also zeroes out ret_exception !
1698	pushl	$0			# ret_addr
1699	pushl	$0			# ret_code
1700	mfpr	$USP,-(sp)		# user sp
1701	callf	$4,_alignment		# call w/o parms so regs may be modified
1702	/*
1703	 * We return here after a successful emulation or an exception.
1704	 * The registers have been restored and we must not alter them
1705	 * before returning to the user.
1706	 */
17072:	mtpr	(sp)+,$USP		# restore user sp
1708	tstl	8(sp)			# Any exception ?
1709	bneq	got_excp		# Yes, reflect it back to user.
1710	moval	8(sp),sp		# pop 2 zeroes pushed above
1711	REST_FPSTAT
1712	xorb2	$EMULATEALIGN,_u+U_EOSYS
1713
1714	bitl	$PSL_T,4(sp)		# check for trace bit set
1715	beql	9f
1716	CHECK_SFE(4)
1717	pushl $0
1718	SAVE_FPSTAT(8)
1719	TRAP(TRCTRAP)
17209:	rei
1721
1722got_excp:				# decode exception
1723	casel	8(sp),$ILL_ADDRMOD,$ALIGNMENT
1724	.align	1
1725L1:
1726	.word	ill_addrmod-L1
1727	.word	ill_access-L1
1728	.word	ill_oprnd-L1
1729	.word	arithmetic-L1
1730	.word	alignment-L1
1731	brw	alignment		# default - shouldn't come here at all !
1732
1733ill_addrmod:				# No other parameters. Set up stack as
1734	moval	8(sp),sp		# the HW would do it in a real case.
1735	REST_FPSTAT
1736	jbr	_Xresadflt
1737ill_oprnd:
1738	moval	8(sp),sp
1739	REST_FPSTAT
1740	jbr	_Xresopflt
1741alignment:
1742	moval	8(sp),sp
1743	REST_FPSTAT
1744	jbr	align_excp	# NB: going to _Xalignflt would cause loop
1745ill_access:
1746	/*
1747	 * Must restore accumulator w/o modifying sp and w/o using
1748	 * registers.  Solution: copy things needed by REST_FPSTAT.
1749	 */
1750	pushl	20(sp)			# The flags longword
1751	pushl	20(sp)			# acc_low
1752	pushl	20(sp)			# acc_high
1753	pushl	20(sp)			# ret_exception ignored by REST_FPSTAT
1754	REST_FPSTAT			# Back where we were with the sp !
1755	movl	(sp),16(sp)		# code for illegal access
1756	movl	4(sp),20(sp)		# original virtual address
1757	moval	16(sp),sp		# Just like the HW would set it up
1758	jbr	_Xprotflt
1759arithmetic:				# same trickery as above
1760	pushl	20(sp)			# The flags longword
1761	pushl	20(sp)			# acc_low
1762	pushl	20(sp)			# acc_high
1763	pushl	20(sp)			# ret_exception ignored by REST_FPSTAT
1764	REST_FPSTAT			# Back where we were with the sp !
1765	movl	(sp),20(sp)		# code for arithmetic exception
1766	moval	20(sp),sp		# Just like the HW would set it up
1767	jbr	_Xarithtrap
1768#endif
1769