xref: /original-bsd/sys/tahoe/tahoe/locore.s (revision 6bf5dd28)
1/*	locore.s	1.8	86/07/16	*/
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	andl2	$~PG_PROT,_rsstkmap
175	orl2	$PG_KW,_rsstkmap		# Make dump stack r/w
176	tstl	dumpflag			# dump only once!
177	bneq	1f
178	movl	$1,dumpflag
179	mtpr	$0,$TBIA
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-r2 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 * (such as in hardclock) understand this, using the
204 * REGSPC definition (and FPSPC defined below).
205 * Finally, many routines, including those expanded
206 * inline depend on this!  Should probably save all
207 * live C compiler temp registers to eliminate potentially
208 * grievous problems caused by incorrect register save masks.
209 */
210#define	REGSPC	(3*4)
211#define	PUSHR	pushl r0; pushl r1; pushl r2;
212#define	POPR	movl (sp)+,r2; movl (sp)+,r1; movl (sp)+,r0;
213
214/*
215 * Floating point state is saved across faults and
216 * interrupts.  The state occupies 4 longwords on
217 * the stack:
218 *	precision indicator (single = 0/double = 1)
219 *	double representation of accumulator
220 *	save accumulator status flag (pcb_savacc)
221 */
222#define	FPSPC	(4*4)
223
224#define SAVE_FPSTAT(_delta) \
225	bitl	$PSL_DBL,_delta(sp); \
226	beql	1f; \
227	pushl	$1; \
228	pushd; \
229	jmp	2f; \
2301:	pushl	$0; \
231	pushl	$0; \
232	stf	-(sp); \
2332:	tstl	_u+PCB_SAVACC; \
234	bneq	3f; \
235	moval	0(sp),_u+PCB_SAVACC; \
236	orl2	$2,8(sp);\
2373:	pushl	$0;
238
239#define REST_FPSTAT \
240	tstl	(sp)+; \
241	bitl	$2,8(sp);\
242	beql	1f;\
243	movl	$0,_u+PCB_SAVACC; \
2441:	bitl	$1,8(sp); \
245	beql	2f; \
246	ldd	(sp); \
247	jmp	3f; \
2482:	ldf	(sp); \
2493:	moval	12(sp),sp;
250
251#define REST_ACC \
252	tstl	_u+PCB_SAVACC; \
253	beql	2f; \
254	movl	_u+PCB_SAVACC,r1; \
255	andl3	$(EXPMASK|SIGNBIT),(r1),-(sp); \
256	cmpl	$0x80000000,(sp)+; \
257	bneq	3f; \
258	clrl	(r1); \
2593:	bitl	$1,8(r1); \
260	beql	1f; \
261	ldd	(r1); \
262	jmp	2f; \
2631:	ldf	(r1); \
2642:	;
265
266	.data
267nofault: .space	4			# bus error non-local goto label
268
269	.text
270SCBVEC(buserr):
271	CHECK_SFE(12)
272	SAVE_FPSTAT(12)
273	incl	_intrcnt+I_BUSERR	# keep stats...
274	pushl	r0			# must save
275	andl3	24(sp),$ERRCD,r0	# grab pushed MER value
276	cmpl	r0,$APE			# address parity error?
277	jneq	1f
278	halt
2791:	cmpl	r0,$VBE			# versabus error?
280	jneq	2f
281	halt
2822:
283	movl	(sp)+,r0		# restore r0 and...
284	bitl	$PSL_CURMOD,4*4+3*4(sp)	# check if happened in user mode?
285	jeql	3f			# yes, then shift stack up for trap...
286	movl	12(sp),16(sp)		# sorry, no space for which-buss...
287	movl	8(sp),12(sp)
288	movl	4(sp),8(sp)
289	movl	0(sp),4(sp)
290	movl	$T_BUSERR,0(sp)		# push trap type code and...
291	jbr	alltraps		# ...merge with all other traps
2923:					# kernel mode, check to see if...
293	tstl	nofault			# ...doing peek/poke?
294	jeql	4f			# nofault set? if so, jump to it...
295	movl	nofault,4*4+2*4(sp)	# ...setup for non-local goto
296	clrl	nofault
297	jbr	5f
2984:
299	PUSHR
300	pushab	7*4(sp)			# address of bus error parameters
301	callf	$8,_buserror
302	POPR
3035:
304	REST_FPSTAT
305	movab	8(sp),sp		# remove bus error parameters
306	rei
307
308SCBVEC(powfail):			# We should be on interrupt stack now.
309	SAVEpwfl()			# save machine state
310	moval	_Xdoadump-SYSTEM,_scb+SCB_DOADUMP
311	halt
312
313SCBVEC(stray):
314	rei
315
316#include "../net/netisr.h"
317	.globl	_netisr
318SCBVEC(netintr):
319	CHECK_SFE(4)
320	SAVE_FPSTAT(4); PUSHR
321#include "imp.h"
322#if NIMP > 0
323	bbc	$NETISR_IMP,_netisr,1f;
324	andl2	$~(1<<NETISR_IMP),_netisr
325	callf	$4,_impintr;
3261:
327#endif
328#ifdef INET
329	bbc	$NETISR_IP,_netisr,1f
330	andl2	$~(1<<NETISR_IP),_netisr
331	callf	$4,_ipintr
3321:
333#endif
334#ifdef NS
335	bbc	$NETISR_NS,_netisr,1f
336	andl2	$~(1<<NETISR_NS),_netisr
337	callf	$4,_nsintr
3381:
339#endif
340	bbc	$NETISR_RAW,_netisr,1f
341	andl2	$~(1<<NETISR_RAW),_netisr
342	callf	$4,_rawintr
3431:
344	incl	_cnt+V_SOFT
345	POPR; REST_FPSTAT
346	rei
347
348SCBVEC(cnrint):
349	CHECK_SFE(4)
350	SAVE_FPSTAT(4); PUSHR;
351	pushl $CPCONS; callf $8,_cnrint;
352	incl	_intrcnt+I_CNR
353	incl	_cnt+V_INTR
354	POPR; REST_FPSTAT;
355	rei
356SCBVEC(cnxint):
357	CHECK_SFE(4)
358	SAVE_FPSTAT(4); PUSHR;
359	pushl $CPCONS; callf $8,_cnxint;
360	incl	_intrcnt+I_CNX
361	incl	_cnt+V_INTR
362	POPR; REST_FPSTAT;
363	rei
364SCBVEC(rmtrint):
365	CHECK_SFE(4)
366	SAVE_FPSTAT(4); PUSHR;
367	pushl $CPREMOT; callf $8,_cnrint;
368	incl	_intrcnt+I_RMTR
369	incl	_cnt+V_INTR
370	POPR; REST_FPSTAT;
371	rei
372SCBVEC(rmtxint):
373	CHECK_SFE(4)
374	SAVE_FPSTAT(4); PUSHR;
375	pushl $CPREMOT; callf $8,_cnxint;
376	incl	_intrcnt+I_RMTX
377	incl	_cnt+V_INTR
378	POPR; REST_FPSTAT;
379	rei
380
381#define PUSHPCPSL	pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp);
382
383SCBVEC(hardclock):
384	tstl	_clk_enable
385	bneq	1f
386	rei
3871:
388	CHECK_SFE(4)
389	SAVE_FPSTAT(4); PUSHR
390	PUSHPCPSL			# push pc and psl
391	callf	$12,_hardclock		# hardclock(pc,psl)
392	incl	_intrcnt+I_CLOCK
393	incl	_cnt+V_INTR		## temp so not to break vmstat -= HZ
394	POPR; REST_FPSTAT
395	rei
396SCBVEC(softclock):
397	CHECK_SFE(4)
398	SAVE_FPSTAT(4); PUSHR;
399	PUSHPCPSL				# push pc and psl
400	callf	$12,_softclock			# softclock(pc,psl)
401	incl	_cnt+V_SOFT
402	POPR; REST_FPSTAT
403	rei
404
405/*
406 * Stray VERSAbus interrupt catch routines
407 */
408	.data
409#define	PJ	.align 2; callf $4,_Xvstray
410	.globl	_catcher
411_catcher:
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	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
421	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
422	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
423	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
424
425	.align	2
426	.globl	_cold
427_cold:	.long	0x3
428
429	.text
430SCBVEC(vstray):
431	.word	0
432	bbc	$0,_cold,2f		# system running?
433	bbc	$1,_cold,1f		# doing autoconfig?
434	jbr	3f			# random interrupt, ignore
4351:
436	mfpr	$IPL,r12		# ...setup br and cvec
437	subl3	$_catcher+7,-8(fp),r11; shar $3,r11,r11
438	addl2	$SCB_DEVBASE,r11
439	jbr	3f
4402:
441	PUSHR
442	subl3	$_catcher+7,-8(fp),r0; shar $3,r0,r0
443	addl3	$SCB_DEVBASE,r0,-(sp);
444	mfpr	$IPL,-(sp)
445	PRINTF(2, "stray intr ipl %x vec %x\n")
446	POPR
4473:	moval	0f,-8(fp); ret		# pop callf frame...
4480:	rei				# ...and return
449
450/*
451 * Trap and fault vector routines
452 */
453#define	TRAP(a)	pushl $T_/**/a; jbr alltraps
454
455/*
456 * Ast delivery (profiling and/or reschedule)
457 */
458/*
459 * When we want to reschedule we will force a
460 * memory fault by setting the ASTBIT of P0LR.
461 * Then, on memory fault if the ASTBIT of the
462 * p0lr is set we will clear it and TRAP(astflt).
463 */
464#define ASTBIT	0x00100000
465#define	P0MASK	0xc0000000
466
467SCBVEC(kspnotval):
468	CHECK_SFE(4)
469	pushl $0;
470	SAVE_FPSTAT(8)
471	TRAP(KSPNOTVAL)
472SCBVEC(privinflt):
473	CHECK_SFE(4)
474	pushl $0;
475	SAVE_FPSTAT(8)
476	TRAP(PRIVINFLT)
477SCBVEC(resopflt):
478	CHECK_SFE(4)
479	pushl $0;
480	SAVE_FPSTAT(8)
481	TRAP(RESOPFLT)
482SCBVEC(resadflt):
483	CHECK_SFE(4)
484	pushl $0;
485	SAVE_FPSTAT(8)
486	TRAP(RESADFLT)
487SCBVEC(bptflt):
488	CHECK_SFE(4)
489	pushl $0;
490	SAVE_FPSTAT(8)
491	TRAP(BPTFLT)
492SCBVEC(tracep):
493	CHECK_SFE(4)
494	pushl $0;
495	SAVE_FPSTAT(8)
496	TRAP(TRCTRAP)
497SCBVEC(alignflt):
498	CHECK_SFE(4)
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	CHECK_SFE(16)
519	SAVE_FPSTAT(16)
520	callf	$4,_fpemulate
521	REST_FPSTAT
522	moval	8(sp),sp	# Pop operand
523	tstl	(sp)		# Stack= PSL, PC, return_code
524	jneq	_Xarithtrap	# If not OK, emulate F.P. exception
525	movab	4(sp),sp	# Else remove return_code and
526	rei
527
528SCBVEC(sfexcep):
529	CHECK_SFE(4)
530	pushl $0
531	SAVE_FPSTAT(8)
532	TRAP(ASTFLT)
533
534SCBVEC(transflt):
535	CHECK_SFE(12)
536	bitl	$1,(sp)+
537	bneq	tableflt
538pageflt:
539	SAVE_FPSTAT(8)
540	TRAP(PAGEFLT)
541tableflt:
542	SAVE_FPSTAT(8)
543	TRAP(TABLEFLT)
544
545#define REST_STACK	movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
546
547alltraps:
548	mfpr	$USP,-(sp);
549	callf	$4,_trap;
550	mtpr	(sp)+,$USP
551	incl	_cnt+V_TRAP
552	REST_STACK			# pop type, code, and fp stuff
553	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
554	rei
555
556SCBVEC(syscall):
557	CHECK_SFE(8)
558	SAVE_FPSTAT(8)
559	pushl	$T_SYSCALL
560	mfpr	$USP,-(sp);
561	callf	$4,_syscall;
562	mtpr	(sp)+,$USP
563	incl	_cnt+V_SYSCALL
564	REST_STACK			# pop type, code, and fp stuff
565	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
566	rei
567
568/*
569 * System page table.
570 *
571 * Mbmap and Usrptmap are enlarged by CLSIZE entries
572 * as they are managed by resource maps starting with index 1 or CLSIZE.
573 */
574#define	vaddr(x)	((((x)-_Sysmap)/4)*NBPG+SYSTEM)
575#define	SYSMAP(mname, vname, npte)			\
576_/**/mname:	.globl	_/**/mname;		\
577	.space	(npte)*4;			\
578	.globl	_/**/vname;			\
579	.set	_/**/vname,vaddr(_/**/mname)
580
581	.data
582	.align	2
583	SYSMAP(Sysmap	,Sysbase	,SYSPTSIZE	)
584	SYSMAP(Forkmap	,forkutl	,UPAGES		)
585	SYSMAP(Xswapmap	,xswaputl	,UPAGES		)
586	SYSMAP(Xswap2map,xswap2utl	,UPAGES		)
587	SYSMAP(Swapmap	,swaputl	,UPAGES		)
588	SYSMAP(Pushmap	,pushutl	,UPAGES		)
589	SYSMAP(Vfmap	,vfutl		,UPAGES		)
590	SYSMAP(CMAP1	,CADDR1		,1		)
591	SYSMAP(CMAP2	,CADDR2		,1		)
592	SYSMAP(mmap	,vmmap		,1		)
593	SYSMAP(alignmap	,alignutl	,1		)	/* XXX */
594	SYSMAP(msgbufmap,msgbuf		,MSGBUFPTECNT	)
595	SYSMAP(Mbmap	,mbutl		,NMBCLUSTERS*CLSIZE+CLSIZE )
596	SYSMAP(camap	,cabase		,(4*32+4)*CLSIZE )
597#ifdef	GPROF
598	SYSMAP(profmap	,profbase	,600*CLSIZE	)
599#endif
600	SYSMAP(ecamap	,calimit	,0		)
601	SYSMAP(VMEMbeg	,vmembeg	,0		)
602	SYSMAP(VMEMmap	,vmem		,VBIOSIZE 	)
603	SYSMAP(VMEMmap1	,vmem1		,VBMEMSIZE	)
604	SYSMAP(VMEMend	,vmemend	,0		)
605	SYSMAP(VBmap	,vbbase		,VBPTSIZE	)
606	SYSMAP(eVBmap	,vbend		,0		)
607	SYSMAP(Usrptmap	,usrpt		,USRPTSIZE+CLSIZE )
608eSysmap:
609	.globl	_Syssize
610	.set	_Syssize,(eSysmap-_Sysmap)/4
611
612	.text
613/*
614 * Initialization
615 *
616 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
617 */
618	.align	2
619	.globl	start
620start:
621	.word	0
622/* set system control block base and system page table params */
623	mtpr	$_scb-SYSTEM,$SCBB
624	mtpr	$_Sysmap-SYSTEM,$SBR
625	mtpr	$_Syssize,$SLR
626/* double map the kernel into the virtual user addresses of phys mem */
627	mtpr	$_Sysmap,$P0BR
628	mtpr	$_Syssize,$P0LR
629	mtpr	$_Sysmap,$P1BR			# against Murphy
630	mtpr	$_Syssize,$P1LR
631/* set ISP */
632	movl	$_intstack-SYSTEM+NISP*NBPG,sp	# still physical
633	mtpr	$_intstack+NISP*NBPG,$ISP
634/* count up memory */
635	clrl	r7
6361:	pushl	$1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
637	ACBL($MAXMEM*1024-1,$64*1024,r7,1b)
6389:
639/* clear memory from kernel bss and pages for proc 0 u. and page table */
640	movab	_edata,r6
641	movab	_end,r5
642	andl2	$~SYSTEM,r6
643	andl2	$~SYSTEM,r5
644	addl2	$(UPAGES*NBPG)+NBPG+NBPG,r5
6451:	clrl	(r6); ACBL(r5,$4,r6,1b)
646/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */
647	orw2	$0x01fff,_trap
648	orw2	$0x01fff,_syscall
649	orw2	$0x01fff,_fpemulate
650	orw2	$0x01ffc,_panic			# for debugging (no r0|r1)
651	callf	$4,_fixctlrmask			# setup for autoconfig
652/* initialize system page table: scb and int stack writeable */
653	clrl	r2
654	movab	eintstack,r1
655	andl2	$~SYSTEM,r1
656	shrl 	$PGSHIFT,r1,r1			# r1-page number of eintstack
657/* make processor storage read/only */
658	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
659	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
660/* other parts of the system are read/write for kernel */
6611:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2];	# data:kernel write+phys=virtual
662	aoblss r1,r2,1b
663/* make rsstk read-only as red zone for interrupt stack */
664	andl2	$~PG_PROT,_rsstkmap
665	orl2	$PG_V|PG_KR,_rsstkmap
666/* make kernel text space read-only */
667	movab	_etext+NBPG-1,r1
668	andl2	$~SYSTEM,r1
669	shrl 	$PGSHIFT,r1,r1
6701:	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]
671	aoblss r1,r2,1b
672/* make kernel data, bss, read-write */
673	movab	_end+NBPG-1,r1
674	andl2	$~SYSTEM,r1
675	shrl 	$PGSHIFT,r1,r1
6761:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]
677	aoblss r1,r2,1b
678/* go to mapped mode, have to change both pc and sp to system addresses */
679	mtpr	$1,$TBIA
680	mtpr	$1,$PADC			# needed by HW parity&ECC logic
681	mtpr	$1,$PACC			# just in case
682	mtpr 	$1,$MME
683	movab	SYSTEM(sp),sp
684	jmp 	*$0f
6850:
686/* disable any interrupts */
687	movl	$0,_intenable
688/* init mem sizes */
689	shrl	$PGSHIFT,r7,_maxmem
690	movl	_maxmem,_physmem
691	movl	_maxmem,_freemem
692/* setup context for proc[0] == scheduler */
693	movab	_end-SYSTEM+NBPG-1,r6
694	andl2	$~(NBPG-1),r6			# make page boundary
695/* setup page table for proc[0] */
696	shrl	$PGSHIFT,r6,r3			# r3 = btoc(r6)
697	orl3	$PG_V|PG_KW,r3,_Usrptmap	# init first upt entry
698	incl	r3				# r3 - next page
699	movab	_usrpt,r0			# r0 - first user page
700	mtpr	r0,$TBIS
701/* init p0br, p0lr */
702	mtpr	r0,$P0BR			# no p0 for proc[0]
703	mtpr	$0,$P0LR
704	mtpr	r0,$P1BR			# no p1 either
705	mtpr	$0,$P1LR
706/* init p2br, p2lr */
707	movab	NBPG(r0),r0
708	movl	$PPAGES-UPAGES,r1
709	mtpr	r1,$P2LR
710	moval	-4*PPAGES(r0),r2
711	mtpr	r2,$P2BR
712/* setup mapping for UPAGES of _u */
713	clrl	r2
714	movl 	$SYSTEM,r1
715	addl2 	$UPAGES,r3
716	jbr 2f
7171:	decl	r3
718	moval	-NBPG(r1),r1	# r1 = virtual add of next (downward) _u page
719	subl2	$4,r0		# r0 = pte address
720	orl3	$PG_V|PG_URKW,r3,(r0)
721	mtpr	r1,$TBIS
7222:	aobleq	$UPAGES,r2,1b
723/* initialize (slightly) the pcb */
724	movab	UPAGES*NBPG(r1),PCB_KSP(r1)	# KSP starts at end of _u
725	movl	r1,PCB_USP(r1)			# USP starts just below _u
726	mfpr	$P0BR,PCB_P0BR(r1)
727	mfpr	$P0LR,PCB_P0LR(r1)
728	mfpr	$P1BR,PCB_P1BR(r1)
729	mfpr	$P1LR,PCB_P1LR(r1)
730	mfpr	$P2BR,PCB_P2BR(r1)
731	mfpr	$P2LR,PCB_P2LR(r1)
732	movl	$CLSIZE,PCB_SZPT(r1)		# init u.u_pcb.pcb_szpt
733	movl	r11,PCB_R11(r1)			# r11 obtained from CP on boot
734	movab	1f,PCB_PC(r1)			# initial pc
735	clrl	PCB_PSL(r1)			# kernel mode, ipl=0
736	shll	$PGSHIFT,r3,r3
737	mtpr	r3,$PCBB			# first pcbb (physical)
738/* go to kernel mode */
739	ldpctx
740	rei					# Actually next instruction:
741/* put signal trampoline code in u. area */
7421:	movab	sigcode,r0
743	movab	_u+PCB_SIGC,r1
744	movl	$19,r2
745	movblk
746/* save boot device in global _bootdev */
747	movl	r10,_bootdev
748/* save reboot flags in global _boothowto */
749	movl	r11,_boothowto
750/* calculate firstaddr, and call main() */
751	movab	_end-SYSTEM+NBPG-1,r0
752	shrl	$PGSHIFT,r0,-(sp)
753	addl2	$UPAGES+1,(sp)			# first physical unused page
754	callf 	$8,_main
755/* proc[1] == /etc/init now running here in kernel mode; run icode */
756	pushl	$PSL_CURMOD			# User mode PSL
757	pushl $0				# PC = 0 (virtual now)
758	rei
759
760/*
761 * Mask for saving/restoring registers on entry to
762 * a user signal handler.  Space for the registers
763 * is reserved in sendsig, so beware if you want
764 * to change the mask.
765 */
766#define	SIGREGS	(R0|R1|R2|R3|R4|R5)
767	.align	2
768	.globl	sigcode
769sigcode:
770	storer	$SIGREGS,16(sp)	# save volatile registers
771	calls	$4*3+4,*12(sp)	# params pushed by sendsig for handler
772	loadr	$SIGREGS,4(sp)	# restore volatile registers
773	movab	24(sp),fp	# use parameter list set up in sendsig
774	kcall	$SYS_sigreturn	# cleanup mask and onsigstack
775	halt			# sigreturn does not return!
776
777	.globl	_icode
778	.globl	_initflags
779	.globl	_szicode
780/*
781 * Icode is copied out to process 1 to exec /etc/init.
782 * If the exec fails, process 1 exits.
783 */
784	.align	2
785_icode:
786	pushab	b`argv-l0(pc)
787l0:	pushab	b`init-l1(pc)
788l1:	pushl	$2
789	movab	(sp),fp
790	kcall	$SYS_execv
791	kcall	$SYS_exit
792
793init:	.asciz	"/etc/init"
794	.align	2
795_initflags:
796	.long	0
797argv:	.long	init+5-_icode
798	.long	_initflags-_icode
799	.long	0
800_szicode:
801	.long	_szicode-_icode
802
803/*
804 * Primitives
805 */
806
807/*
808 * badaddr(addr, len)
809 *	see if access addr with a len type instruction causes a machine check
810 *	len is length of access (1=byte, 2=short, 4=long)
811 *	r0 = 0 means good(exists); r0 =1 means does not exist.
812 */
813ENTRY(badaddr, R3|R4)
814	mfpr	$IPL,r1
815	mtpr	$HIGH,$IPL
816	movl	_scb+SCB_BUSERR,r2
817	movl	4(fp),r3
818	movl	8(fp),r4
819	movab	9f,_scb+SCB_BUSERR
820	bbc	$0,r4,1f; tstb	(r3)
8211:	bbc	$1,r4,1f; tstw	(r3)
8221:	bbc	$2,r4,1f; tstl	(r3)
8231:	clrl	r0
8242:	movl	r2,_scb+SCB_BUSERR
825	mtpr	r1,$IPL
826	ret
827
828	.align	2
8299:				# catch buss error (if it comes)
830	andl3	4(sp),$ERRCD,r0
831	cmpl	r0,$APE
832	jneq	1f
833	halt			# address parity error
8341:	cmpl	r0,$VBE
835	jneq	1f
836	halt			# Versabus error
8371:
838	movl	$1,r0		# Anything else = bad address
839	movab	8(sp),sp	# discard buss error trash
840	movab	2b,(sp)		# new program counter on stack.
841	rei
842
843/*
844 * badcyaddr(addr)
845 *	see if access tape master controller addr causes a bus error
846 *	r0 = 0: no error; r0 = 1: timeout error.
847 */
848ENTRY(badcyaddr, 0)
849	mfpr	$IPL,r1
850	mtpr	$HIGH,$IPL
851	clrl	r2
852	movab	2f,nofault
853	movob	$-1, *4(fp)
8541:	aobleq	$1000, r2, 1b
855	clrl	nofault			# made it w/o bus error
856	clrl	r0
857	jbr	3f
8582:	movl	$1,r0
8593:	mtpr	r1,$IPL
860	ret
861
862/*
863 * peek(addr)
864 *	fetch word and catch any bus error
865 */
866ENTRY(peek, 0)
867	mfpr	$IPL,r1
868	mtpr	$0x18,$IPL	# not reentrant
869	movl	4(fp),r2
870	movab	1f,nofault
871	movw	(r2),r0
872	clrl	nofault
873	andl2	$0xffff,r0
874	jbr	2f
8751:	movl	$-1,r0		# bus error
8762:	mtpr	r1,$IPL
877	ret
878
879/*
880 * poke(addr, val)
881 *	write word and catch any bus error
882 */
883ENTRY(poke, R3)
884	mfpr	$IPL,r1
885	mtpr	$0x18,$IPL	# not reentrant
886	movl	4(fp),r2
887	movl	8(fp),r3
888	clrl	r0
889	movab	1f,nofault
890	movw	r3,(r2)
891	clrl	nofault
892	jbr	2f
8931:	movl	$-1,r0		# bus error
8942:	mtpr	r1,$IPL
895	ret
896
897/*
898 * Copy a potentially overlapping block of memory.
899 *
900 * ovbcopy(src, dst, count)
901 *	caddr_t src, dst; unsigned count;
902 */
903ENTRY(ovbcopy, R3|R4)
904	movl	4(fp),r0
905	movl	8(fp),r1
906	movl	12(fp),r2
907	cmpl	r0,r1
908	bgtru	1f			# normal forward case
909	beql	2f			# equal, nothing to do
910	addl2	r2,r0			# may be overlapping
911	cmpl	r0,r1
912	bgtru	3f
913	subl2	r2,r0			# normal forward case
9141:
915	movblk
9162:
917	ret
9183:
919	addl2	r2,r1			# overlapping, must do backwards
920	subl3	r0,r1,r3
921	movl	r2,r4
922	jbr	5f
9234:
924	subl2	r3,r0
925	subl2	r3,r1
926	movl	r3,r2
927	movblk
928	subl2	r3,r0
929	subl2	r3,r1
930	subl2	r3,r4
9315:
932	cmpl	r4,r3
933	jgtr	4b
934	movl	r4,r2
935	subl2	r2,r0
936	subl2	r2,r1
937	movblk
938	ret
939
940/*
941 * Copy a null terminated string from the user address space into
942 * the kernel address space.
943 *
944 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
945 */
946ENTRY(copyinstr, R3|R4|R5)
947	movl	12(fp),r5		# r5 = max length
948	jlss	8f
949	movl	4(fp),r0		# r0 = user address
950	movl	r0,r3			# r3 = copy of src for null byte test
951	andl3	$(NBPG*CLSIZE-1),r0,r2	# r2 = bytes on first page
952	subl3	r2,$(NBPG*CLSIZE),r2
953	movl	8(fp),r1		# r1 = kernel address
9541:
955	cmpl	r5,r2			# r2 = min(bytes on page, length left);
956	jgeq	2f
957	movl	r5,r2
9582:
959	prober	$1,(r0),r2		# bytes accessible?
960	jeql	8f
961	subl2	r2,r5			# update bytes left count
962	addl2	r2,r3			# calculate src+count
963	movs3				# copy in next piece
964	subl3	r0,r3,r2		# null byte found?
965	jneq	3f
966	movl	$(NBPG*CLSIZE),r2	# check next page
967	tstl	r5			# run out of space?
968	jneq	1b
969	movl	$ENOENT,r0		# set error code and return
970	jbr	9f
9713:
972	tstl	16(fp)			# return length?
973	beql	4f
974	subl3	r5,12(fp),r5		# actual len = maxlen - unused pages
975	subl2	r2,r5			#	- unused on this page
976	addl3	$1,r5,*16(fp)		#	+ the null byte
9774:
978	clrl	r0
979	ret
9808:
981	movl	$EFAULT,r0
9829:
983	tstl	16(fp)
984	beql	1f
985	subl3	r5,12(fp),*16(fp)
9861:
987	ret
988
989/*
990 * Copy a null terminated string from the kernel
991 * address space to the user address space.
992 *
993 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
994 */
995ENTRY(copyoutstr, R3|R4|R5)
996	movl	12(fp),r5		# r5 = max length
997	jlss	8b
998	movl	4(fp),r0		# r0 = kernel address
999	movl	r0,r3			# r3 = copy of src for null byte test
1000	movl	8(fp),r1		# r1 = user address
1001	andl3	$(NBPG*CLSIZE-1),r1,r2	# r2 = bytes on first page
1002	subl3	r2,$(NBPG*CLSIZE),r2
10031:
1004	cmpl	r5,r2			# r2 = min(bytes on page, length left);
1005	jgeq	2f
1006	movl	r5,r2
10072:
1008	probew	$1,(r1),r2		# bytes accessible?
1009	jeql	8b
1010	subl2	r2,r5			# update bytes left count
1011	addl2	r2,r3			# calculate src+count
1012#ifdef notdef
1013	movs3				# copy out next piece
1014#else
1015	tstl	r2
1016	beql	6f
10174:
1018	movb	(r0),(r1)
1019	beql	5f
1020	incl	r0
1021	incl	r1
1022	decl	r2
1023	bneq	4b
1024	jbr	6f
10255:
1026	incl	r1
1027	decl	r2
10286:
1029#endif
1030	subl3	r0,r3,r2		# null byte found?
1031	jneq	3b
1032	movl	$(NBPG*CLSIZE),r2	# check next page
1033	tstl	r5			# run out of space?
1034	jneq	1b
1035	movl	$ENOENT,r0		# set error code and return
1036	jbr	9b
1037
1038/*
1039 * Copy a null terminated string from one point to another in
1040 * the kernel address space.
1041 *
1042 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1043 */
1044ENTRY(copystr, R3|R4|R5)
1045	movl	12(fp),r5		# r5 = max length
1046	jlss	8b
1047	movl	4(fp),r0		# r0 = src address
1048	movl	r0,r3			# r3 = copy of src for null byte test
1049	movl	8(fp),r1		# r1 = dest address
10501:
1051	movzwl	$65535,r2		# r2 = bytes in first chunk
1052	cmpl	r5,r2			# r2 = min(bytes in chunk, length left);
1053	jgeq	2f
1054	movl	r5,r2
10552:
1056	subl2	r2,r5			# update bytes left count
1057	addl2	r2,r3			# calculate src+count
1058	movs3				# copy next piece
1059	subl3	r0,r3,r2		# null byte found?
1060	jneq	3b
1061	tstl	r5			# run out of space?
1062	jneq	1b
1063	movl	$ENOENT,r0		# set error code and return
1064	jbr	9b
1065
1066/*
1067 * Copy a block of data from the user address space into
1068 * the kernel address space.
1069 *
1070 * copyin(fromaddr, toaddr, count)
1071 */
1072ENTRY(copyin, 0)
1073	movl	12(fp),r0		# copy length
1074	blss	9f
1075	movl	4(fp),r1		# copy user address
1076	cmpl	$(CLSIZE*NBPG),r0	# probing one page or less ?
1077	bgeq	2f			# yes
10781:
1079	prober	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible ?
1080	beql	9f			# no
1081	addl2	$(CLSIZE*NBPG),r1	# incr user address ptr
1082	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
10832:
1084	prober	$1,(r1),r0		# bytes accessible ?
1085	beql	9f			# no
1086	MOVC3(4(fp),8(fp),12(fp))
1087	clrl	r0
1088	ret
10899:
1090	movl	$EFAULT,r0
1091	ret
1092
1093/*
1094 * Copy a block of data from the kernel
1095 * address space to the user address space.
1096 *
1097 * copyout(fromaddr, toaddr, count)
1098 */
1099ENTRY(copyout, 0)
1100	movl	12(fp),r0		# get count
1101	blss	9b
1102	movl	8(fp),r1		# get user address
1103	cmpl	$(CLSIZE*NBPG),r0	# can do in one probew?
1104	bgeq	2f			# yes
11051:
1106	probew	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible?
1107	beql	9b			# no
1108	addl2	$(CLSIZE*NBPG),r1	# increment user address
1109	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
11102:
1111	probew	$1,(r1),r0		# bytes accessible?
1112	beql	9b			# no
1113	MOVC3(4(fp),8(fp),12(fp))
1114	clrl	r0
1115	ret
1116
1117/*
1118 * non-local goto's
1119 */
1120#ifdef notdef
1121ENTRY(setjmp, 0)
1122	movl	4(fp),r0
1123	movl	(fp),(r0); addl2 $4,r0		# save fp
1124	movl	-8(fp),(r0)			# save pc
1125	clrl	r0
1126	ret
1127#endif
1128
1129ENTRY(longjmp, 0)
1130	movl	4(fp),r0
1131	movl	(r0),newfp; addl2 $4,r0		# must save parameters in memory
1132	movl	(r0),newpc			# as all regs may be clobbered.
11331:
1134	cmpl	fp,newfp			# are we there yet?
1135	bgequ	2f				# yes
1136	moval	1b,-8(fp)			# redirect return pc to us!
1137	ret					# pop next frame
11382:
1139	beql	3f				# did we miss our frame?
1140	pushab	4f				# yep ?!?
1141	callf	$8,_panic
11423:
1143	movl	newpc,r0			# all done, just return
1144	jmp	(r0)				# to setjmp `ret'
1145
1146	.data
1147newpc:	.space	4
1148newfp:	.space	4
11494:	.asciz	"longjmp"
1150
1151/*
1152 * setjmp that saves all registers as the call frame may not
1153 * be available to recover them in the usual manner by longjmp.
1154 * Called before swapping out the u. area, restored by resume()
1155 * below.
1156 */
1157ENTRY(savectx, 0)
1158	movl	4(fp),r2
1159	storer	$0x1ff8,(r2); addl2 $40,r2	# r3-r12
1160	movl	(fp),(r2); addl2 $4,r2		# fp
1161	movab	8(fp),(r2); addl2 $4,r2		# sp
1162	movl	-8(fp),(r2)			# pc
1163	clrl	r0
1164	ret
1165
1166	.globl	_whichqs
1167	.globl	_qs
1168	.globl	_cnt
1169
1170	.globl	_noproc
1171	.comm	_noproc,4
1172	.globl	_runrun
1173	.comm	_runrun,4
1174/*
1175 * The following primitives use the fancy TAHOE instructions.
1176 * _whichqs tells which of the 32 queues _qs
1177 * have processes in them.  setrq puts processes into queues, remrq
1178 * removes them from queues.  The running process is on no queue,
1179 * other processes are on a queue related to p->p_pri, divided by 4
1180 * actually to shrink the 0-127 range of priorities into the 32 available
1181 * queues.
1182 */
1183
1184/*
1185 * setrq(p), using fancy TAHOE instructions.
1186 *
1187 * Call should be made at spl8(), and p->p_stat should be SRUN
1188 */
1189ENTRY(setrq, 0)
1190	movl	4(fp),r0
1191	tstl	P_RLINK(r0)		## firewall: p->p_rlink must be 0
1192	beql	set1			##
1193	pushab	set3			##
1194	callf	$8,_panic		##
1195set1:
1196	movzbl	P_PRI(r0),r1		# put on queue which is p->p_pri / 4
1197	shar	$2,r1,r1
1198	shal	$1,r1,r2
1199	moval	_qs[r2],r2
1200	insque	(r0),*4(r2)		# at end of queue
1201	shal	r1,$1,r1
1202	orl2	r1,_whichqs		# mark queue non-empty
1203	ret
1204
1205set3:	.asciz	"setrq"
1206
1207/*
1208 * remrq(p), using fancy TAHOE instructions
1209 *
1210 * Call should be made at spl8().
1211 */
1212ENTRY(remrq, 0)
1213	movl	4(fp),r0
1214	movzbl	P_PRI(r0),r1
1215	shar	$2,r1,r1
1216	bbs	r1,_whichqs,rem1
1217	pushab	rem3			# it wasn't recorded to be on its q
1218	callf	$8,_panic
1219rem1:
1220	remque	(r0)
1221	bneq	rem2			# q not empty yet
1222	shal	r1,$1,r1
1223	mcoml	r1,r1
1224	andl2	r1,_whichqs		# mark queue empty
1225rem2:
1226	clrl	P_RLINK(r0)		## for firewall checking
1227	ret
1228
1229rem3:	.asciz	"remrq"
1230
1231/*
1232 * Masterpaddr is the p->p_addr of the running process on the master
1233 * processor.  When a multiprocessor system, the slave processors will have
1234 * an array of slavepaddr's.
1235 */
1236	.globl	_masterpaddr
1237	.data
1238_masterpaddr: .long	0
1239
1240	.text
1241sw0:	.asciz	"swtch"
1242/*
1243 * swtch(), using fancy tahoe instructions
1244 */
1245ENTRY(swtch, 0)
1246	movl	(fp),fp			# prepare for rei
1247	movl	(sp),4(sp)		# saved pc
1248	tstl	(sp)+
1249	movpsl	4(sp)
1250	movl	$1,_noproc
1251	clrl	_runrun
1252mtpr0:	mtpr	$0,$IPL			# must allow interrupts here
1253sw1:	ffs	_whichqs,r0		# look for non-empty queue
1254	bgeq	sw1a
1255	brb	sw1			# this is an idle loop!
1256sw1a:	mtpr	$0x18,$IPL		# lock out all so _whichqs==_qs
1257	bbc	r0,_whichqs,mtpr0	# proc moved via lbolt interrupt
1258	shal	$1,r0,r1
1259	moval	_qs[r1],r1
1260	movl	(r1),r2			# r2 = p = highest pri process
1261	remque	*(r1)
1262	bvc	sw2			# make sure something was there
1263sw1b:	pushab	sw0
1264	callf	$8,_panic
1265sw2:	bneq	sw3
1266	shal	r0,$1,r1
1267	mcoml	r1,r1
1268	andl2	r1,_whichqs		# no more procs in this queue
1269sw3:
1270	clrl	_noproc
1271	tstl	P_WCHAN(r2)		## firewalls
1272	bneq	sw1b			##
1273	cmpb	P_STAT(r2),$SRUN	##
1274	bneq	sw1b			##
1275	clrl	P_RLINK(r2)		##
1276	movl	*P_ADDR(r2),r0
1277	movl	r0,_masterpaddr
1278	shal	$PGSHIFT,r0,r0		# r0 = pcbb(p)
1279#ifdef notdef
1280	mfpr	$PCBB,r1		# resume of current proc is easy
1281	cmpl	r0,r1
1282	beql	res0
1283#endif
1284	incl	_cnt+V_SWTCH
1285	brb	swresume
1286	/* fall into... */
1287
1288	.globl	_prevpcb
1289_prevpcb: .long	0
1290	.text
1291/*
1292 * resume(pf)
1293 */
1294ENTRY(resume, 0)
1295	shal	$PGSHIFT,4(fp),r0	# r0 = pcbb(pf)
1296	movl	(fp),fp			# prepare for rei
1297	movl	(sp)+,4(sp)		# saved pc
1298	tstl	(sp)+
1299	movpsl	4(sp)
1300swresume:
1301	mtpr	$0x18,$IPL		# no interrupts, please
1302	movl	_CMAP2,_u+PCB_CMAP2	# yech
1303	REST_ACC			# restore original accumulator
1304	svpctx
1305	mtpr	r0,$PCBB
1306	ldpctx
1307	movl	_u+PCB_CMAP2,_CMAP2	# yech
1308	mtpr	$_CADDR2,$TBIS
1309res0:
1310	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1311	tstl	P_CKEY(r2)		# does proc have code key?
1312	bneq	1f
1313	callf	$4,_getcodekey		# no, give him one
1314	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1315	movl	r0,P_CKEY(r2)
13161:
1317	tstl	P_DKEY(r2)		# does proc have data key?
1318	bneq	1f
1319	callf	$4,_getdatakey		# no, give him one
1320	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1321	movl	r0,P_DKEY(r2)
13221:
1323	mtpr	P_CKEY(r2),$CCK		# set code cache key
1324	mtpr	P_DKEY(r2),$DCK		# set data cache key
1325	tstl	_u+PCB_SSWAP
1326	bneq	res1
1327	rei
1328res1:					# longjmp to saved context
1329	movl	_u+PCB_SSWAP,r2
1330	clrl	_u+PCB_SSWAP
1331	loadr	$0x3ff8,(r2); addl2 $44,r2	# restore r3-r13 (r13=fp)
1332	movl	(r2),r1; addl2 $4,r2	# fetch previous sp ...
1333	movab	(sp),r0			# ... and current sp and
1334	cmpl	r1,r0			# check for credibility,
1335	bgequ	1f			# if further up stack ...
1336	pushab 2f; callf $8,_panic	# ... panic
1337	/*NOTREACHED*/
13381:					# sp ok, complete return
1339	movl	r1,sp			# restore sp
1340	movl	(r2),(sp)		# return address
1341	movl	$PSL_PRVMOD,4(sp)	# kernel mode, ipl 0
1342	rei
13432:	.asciz	"ldctx"
1344
1345/*
1346 * {fu,su},{byte,word}
1347 */
1348ENTRY(fuword, 0)
1349	movl	4(fp), r1
1350	prober	$1,(r1),$4		# check access
1351	beql	fserr			# page unreadable
1352	bitl	$1,r1			# check byte alignment
1353	bneq	2f			# odd, do byte-word-byte
1354	bitl	$2,r1			# check word alignment
1355	bneq	1f			# odd, do in 2 words
1356	movl	(r1),r0			# move longword
1357	ret
13581:
1359	movw	(r1),r0			# move two words
1360	shal	$16,r0,r0
1361	movzwl	2(r1),r1		# orw2 sign extends
1362	orl2	r1,r0
1363	ret
13642:
1365	movb	(r1),r0			# move byte-word-byte
1366	shal	$24,r0,r0
1367	movzwl	1(r1),r2		# orw2 sign extends
1368	shal	$8,r2,r2
1369	movzbl	3(r1),r1		# orb2 sign extends
1370	orl2	r2,r1
1371	orl2	r1,r0
1372	ret
1373fserr:
1374	mnegl	$1,r0
1375	ret
1376
1377ENTRY(fubyte, 0)
1378	prober	$1,*4(fp),$1
1379	beql	fserr
1380	movzbl	*4(fp),r0
1381	ret
1382
1383ENTRY(suword, 0)
1384	movl	4(fp), r0
1385	probew	$1,(r0),$4		# check access
1386	beql	fserr			# page unwritable
1387	bitl	$1,r0			# check byte alignment
1388	bneq	1f			# odd byte boundary
1389	bitl	$2,r0			# check word alignment
1390	beql	2f			# longword aligned
1391	movw	8(fp),(r0)		# move two words
1392	movw	10(fp),2(r0)
1393	jbr	3f
13941:
1395	movb	8(fp),(r0)
1396	movb	9(fp),1(r0)
1397	movb	10(fp),2(r0)
1398	movb	11(fp),3(r0)
1399	jbr	3f
14002:
1401	movl	8(fp),(r0)
14023:
1403	clrl	r0
1404	ret
1405
1406ENTRY(subyte, 0)
1407	probew	$1,*4(fp),$1
1408	beql	fserr
1409	movb	11(fp),*4(fp)
1410	clrl	r0
1411	ret
1412
1413/*
1414 * Copy 1 relocation unit (NBPG bytes)
1415 * from user virtual address to physical address
1416 */
1417ENTRY(copyseg, 0)
1418	orl3	$PG_V|PG_KW,8(fp),_CMAP2
1419	mtpr	$_CADDR2,$TBIS	# invalidate entry for copy
1420	MOVC3(4(fp),$_CADDR2,$NBPG)
1421	ret
1422
1423/*
1424 * Clear a page of memory.  The page frame is specified.
1425 *
1426 * clearseg(pf);
1427 */
1428ENTRY(clearseg, 0)
1429	orl3	$PG_V|PG_KW,4(fp),_CMAP1	# Maps to virtual addr CADDR1
1430	mtpr	$_CADDR1,$TBIS
1431	movl	$255,r0				# r0 = limit
1432	clrl	r1				# r1 = index of cleared long
14331:
1434	clrl	_CADDR1[r1]
1435	aobleq	r0,r1,1b
1436	ret
1437
1438/*
1439 * Check user mode read/write access.
1440 *
1441 * useracc(addr, count, mode)
1442 *	caddr_t addr; int count, mode;
1443 * mode = 0	write access
1444 * mode = 1	read access
1445 */
1446ENTRY(useracc, 0)
1447	movl	$1,r2			# r2 = 'user mode' for probew/probew
1448probes:
1449	movl	4(fp),r0		# get va
1450	movl	8(fp),r1		# count
1451	tstl	12(fp)			# test for read access ?
1452	bneq	userar			# yes
1453	cmpl	$(CLSIZE*NBPG),r1	# can we do it in one probe ?
1454	bgeq	uaw2			# yes
1455uaw1:
1456	probew	r2,(r0),$(CLSIZE*NBPG)
1457	beql	uaerr			# no access
1458	addl2	$(CLSIZE*NBPG),r0
1459	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1)
1460uaw2:
1461	probew	r2,(r0),r1
1462	beql	uaerr
1463	movl	$1,r0
1464	ret
1465userar:
1466	cmpl	$(CLSIZE*NBPG),r1
1467	bgeq	uar2
1468uar1:
1469	prober	r2,(r0),$(CLSIZE*NBPG)
1470	beql	uaerr
1471	addl2	$(CLSIZE*NBPG),r0
1472	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1)
1473uar2:
1474	prober	r2,(r0),r1
1475	beql	uaerr
1476	movl	$1,r0
1477	ret
1478uaerr:
1479	clrl	r0
1480	ret
1481
1482/*
1483 * Check kernel mode read/write access.
1484 *
1485 * kernacc(addr, count, mode)
1486 *	caddr_t addr; int count, mode;
1487 * mode = 0	write access
1488 * mode = 1	read access
1489 */
1490ENTRY(kernacc, 0)
1491	clrl	r2		# r2 = 0 means kernel mode probe.
1492	jbr	probes		# Dijkstra would get gastric distress here.
1493
1494/*
1495 * addupc - increment some histogram counter
1496 *	in the profiling buffer
1497 *
1498 * addupc(pc, prof, delta)
1499 *	long pc; short delta; struct uprof *prof;
1500 *
1501 * struct uprof {		# profile arguments
1502 * 	short	*r_base;	# buffer base
1503 * 	unsigned pr_size;	# buffer size
1504 * 	unsigned pr_off;	# pc offset
1505 * 	unsigned pr_scale;	# pc scaling
1506 * }
1507 */
1508ENTRY(addupc, 0)
1509	movl	8(fp),r2		# r2 points to structure
1510	subl3	8(r2),4(fp),r0		# r0 = PC - lowpc
1511	jlss	9f			# PC < lowpc , out of range !
1512	shrl	$1,r0,r0		# the unit is words
1513	shrl	$1,12(r2),r1		# ditto for scale
1514	emul	r1,r0,$0,r0
1515	shrq	$14,r0,r0
1516	tstl	r0			# too big
1517	jneq	9f
1518	cmpl	r1,4(r2)		# Check buffer overflow
1519	jgequ	9f
1520	probew	$1,*0(r2)[r1],$2	# counter accessible?
1521	jeql	9f
1522	shrl	$1,r1,r1		# make r1 word index
1523	addw2	14(fp),*0(r2)[r1]
15249:	ret
1525
1526/*
1527 * scanc(size, cp, table, mask)
1528 */
1529ENTRY(scanc, R3|R4)
1530	movl	8(fp),r0		# r0 = cp
1531	addl3	4(fp),r0,r2		# end = &cp[size]
1532	movl	12(fp),r1		# r1 = table
1533	movb	19(fp),r4		# r4 = mask
1534	decl	r0			# --cp
1535	jbr	0f			# just like Fortran...
15361:					# do {
1537	movzbl	(r0),r3
1538	bitb	r4,(r1)[r3]		#	if (table[*cp] & mask)
1539	jneq	2f			#		break;
15400:	aoblss	r2,r0,1b		# } while (++cp < end);
15412:
1542	subl3	r0,r2,r0; ret		# return (end - cp);
1543
1544/*
1545 * skpc(mask, size, cp)
1546 */
1547ENTRY(skpc, 0)
1548	movl	12(fp),r0		# r0 = cp
1549	addl3	8(fp),r0,r1		# r1 = end = &cp[size];
1550	movb	7(fp),r2		# r2 = mask
1551	decl	r0			# --cp;
1552	jbr	0f
15531:					# do
1554	cmpb	(r0),r2			#	if (*cp != mask)
1555	jneq	2f			#		break;
15560:	aoblss	r1,r0,1b		# while (++cp < end);
15572:
1558	subl3	r0,r1,r0; ret		# return (end - cp);
1559
1560#ifdef notdef
1561/*
1562 * locc(mask, size, cp)
1563 */
1564ENTRY(locc, 0)
1565	movl	12(fp),r0		# r0 = cp
1566	addl3	8(fp),r0,r1		# r1 = end = &cp[size]
1567	movb	7(fp),r2		# r2 = mask
1568	decl	r0			# --cp;
1569	jbr	0f
15701:					# do
1571	cmpb	(r0),r2			#	if (*cp == mask)
1572	jeql	2f			#		break;
15730:	aoblss	r1,r0,1b		# while (++cp < end);
15742:
1575	subl3	r0,r1,r0; ret		# return (end - cp);
1576#endif
1577