xref: /original-bsd/sys/vax/vax/locore.s (revision e718337e)
1/*
2 * Copyright (c) 1980, 1986 Regents of the University of California.
3 * All rights reserved.  The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 *	@(#)locore.s	7.26 (Berkeley) 10/19/90
7 */
8
9#include "psl.h"
10#include "pte.h"
11
12#include "errno.h"
13#include "syscall.h"
14#include "cmap.h"
15
16#include "mtpr.h"
17#include "trap.h"
18#include "cpu.h"
19#include "nexus.h"
20#include "cons.h"
21#include "clock.h"
22#include "ioa.h"
23#include "ka630.h"
24#include "ka650.h"
25#include "ka820.h"
26#include "../vaxuba/ubareg.h"
27
28#include "dz.h"
29#include "dp.h"
30#include "uu.h"
31#include "ps.h"
32#include "mba.h"
33#include "uba.h"
34
35	.set	HIGH,0x1f	# mask for total disable
36	.set	MCKVEC,4	# offset into scb of machine check vector
37	.set	NBPG,512
38	.set	PGSHIFT,9
39	.set	SYSTEM,0x80000000	# virtual address of system start
40
41	.set	NISP,3		# number of interrupt stack pages
42
43/*
44 * User structure is UPAGES at top of user space.
45 */
46	.globl	_u
47	.set	_u,0x80000000 - UPAGES*NBPG
48
49	.globl	_intstack
50_intstack:
51	.space	NISP*NBPG
52eintstack:
53
54/*
55 * Do a dump.
56 * Called by auto-restart.
57 * May be called manually.
58 */
59	.align	2
60	.globl	_doadump
61	.globl	_msgbufmapped
62_doadump:
63	nop; nop				# .word 0x0101
64#define	_rpbmap	_Sysmap				# rpb, scb, UNIvec[], istack*4
65	bicl2	$PG_PROT,_rpbmap
66	bisl2	$PG_KW,_rpbmap
67	mtpr	$0,$TBIA
68	tstl	_rpb+RP_FLAG			# dump only once!
69	bneq	1f
70	incl	_rpb+RP_FLAG
71	movl	sp,erpb
72	movab	erpb,sp
73	mfpr	$PCBB,-(sp)
74	mfpr	$MAPEN,-(sp)
75	mfpr	$IPL,-(sp)
76	clrl	_msgbufmapped
77	mtpr	$0,$MAPEN
78	mtpr	$HIGH,$IPL
79	pushr	$0x3fff
80	calls	$0,_dumpsys
811:
82	clrl	r11				# boot flags
83	calls	$0,_vaxboot
84	halt
85
86/*
87 * Interrupt vector routines
88 */
89	.globl	_waittime
90
91#define	SCBVEC(name)	.align 2; .globl _X/**/name; _X/**/name
92#define	PANIC(msg)	clrl _waittime; pushab 1f; \
93			calls $1,_panic; 1: .asciz msg
94#define	PRINTF(n,msg)	pushab 1f; calls $n+1,_printf; MSG(msg)
95#define	MSG(msg)	.data; 1: .asciz msg; .text
96#define	PUSHR		pushr $0x3f
97#define	POPR		popr $0x3f
98
99	.data
100nofault: .long	0	# where to go on predicted machcheck
101	.text
102SCBVEC(machcheck):
103	tstl	nofault
104	bneq	1f
105	PUSHR; pushab 6*4(sp); calls $1,_machinecheck; POPR;
106	addl2 (sp)+,sp; rei
107	.align	2
1081:
109	casel	_cpu,$1,$VAX_MAX
1100:
111	.word	8f-0b		# 1 is 780
112	.word	5f-0b		# 2 is 750
113	.word	5f-0b		# 3 is 730
114	.word	7f-0b		# 4 is 8600
115	.word	5f-0b		# 5 is 8200
116	.word	1f-0b		# 6 is 8800 (unsupported)
117	.word	1f-0b		# 7 is 610  (unsupported)
118	.word	1f-0b		# 8 is 630
119	.word	1f-0b		# 9 is ???
120	.word	9f-0b		# 10 is 650
1215:
122#if defined(VAX8200) || defined(VAX750) || defined(VAX730)
123	mtpr	$0xf,$MCESR
124#endif
125	brb	1f
1267:
127#if VAX8600
128	mtpr	$0,$EHSR
129#endif
130	brb	1f
1318:
132#if VAX780
133	mtpr	$0,$SBIFS
134#endif
135	brb	1f
1369:
137#if VAX650
138	bitl	$PG_V,_KA650MERRmap
139	beql	1f	# don't bother clearing err reg if not mapped in
140	movl	$DSER_CLEAR,_ka650merr+4
141#endif
1421:
143	addl2	(sp)+,sp		# discard mchchk trash
144	movl	nofault,(sp)
145	rei
146
147SCBVEC(kspnotval):
148	PANIC("KSP not valid");
149SCBVEC(powfail):
150	halt
151SCBVEC(chme): SCBVEC(chms): SCBVEC(chmu):
152	PANIC("CHM? in kernel");
153
154SCBVEC(nex0zvec):
155	PUSHR
156	clrl	r0
157	brb	1f
158SCBVEC(nex1zvec):
159	PUSHR
160	movl	$1,r0
1611:
162	cmpl	_cpu,$VAX_8600		# this is a frill
163	beql	2f
164	mfpr	$IPL,-(sp)
165	PRINTF(1, "nexus stray intr ipl%x\n")
166	POPR
167	rei
1682:
169	pushl	r0
170	mfpr	$IPL,-(sp)
171	PRINTF(2, "nexus stray intr ipl%x sbia%d\n")
172	POPR
173	rei
174
175SCBVEC(cmrd):
176	PUSHR; calls $0,_memerr; POPR; rei
177
178SCBVEC(wtime):			/* sbi0err on 8600 */
179#if VAX8600
180	cmpl	_cpu,$VAX_8600
181	bneq	wtimo
182	PANIC("sbia0 error")
183wtimo:
184#endif
185	PUSHR; pushl 6*4(sp); PRINTF(1, "write timeout %x\n"); POPR
186	PANIC("wtimo")
187
188SCBVEC(sbi0fail):
189	PANIC("sbia0 fail")
190SCBVEC(sbi0alert):
191#if VAX8200
192	cmpl	_cpu,$VAX_8200
193	bneq	alert
194	PUSHR; calls $0,_rxcdintr; POPR; rei
195alert:
196#endif
197	PANIC("sbia0 alert")
198SCBVEC(sbi0fault):
199	PANIC("sbia0 fault")
200
201#ifdef notyet
202#if VAX8600
203SCBVEC(sbi1fail):
204	PANIC("sbia1 fail")
205SCBVEC(sbi1alert):
206	PANIC("sbia1 alert")
207SCBVEC(sbi1fault):
208	PANIC("sbia1 fault")
209SCBVEC(sbi1err):
210	PANIC("sbia1 error")
211#endif
212#endif
213
214/*
215 * BI 0 bus error (8200), or SBI silo compare error (others)
216 * VMS boot leaves us 1 BI error to ignore.
217 */
218#if VAX8200 && 0
219	.data
220	.align	2
221_ignorebi: .globl _ignorebi
222	.long	1
223	.text
224#endif VAX8200
225
226SCBVEC(sbisilo):
227#if VAX8200
228	cmpl	_cpu,$VAX_8200
229	bneq	sbisilo
230#if 0
231	blbs	_ignorebi,1f
232#else
233	blbs	_cold,1f
234#endif
235	PUSHR; pushl $0; calls $1,_bi_buserr; POPR
2361:
237	rei
238#endif
239sbisilo:
240	PANIC("sbi silo compare error")
241
242/*
243 * SCB stray interrupt catcher.  Compute and print the actual
244 * SCB vector (for fault diagnosis).
245 */
246	.align	2
247_scbstray: .globl _scbstray
248#define	PJ	PUSHR;jsb 1f
249	/* 128 of 'em */
250	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
251	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
252	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
253	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
254	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
255	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
256	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
257	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
258#if VAX8600
259	/* and another 128, for the second SBIA's scb */
260	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
261	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
262	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
263	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
264	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
265	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
266	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
267	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
268#endif
269#undef PJ
2701:
271	subl3	$_scbstray+8,(sp)+,r0
272	mfpr	$IPL,-(sp)
273	ashl	$-1,r0,-(sp)
274/* call a C handler instead? perhaps later */
275	PRINTF(2, "stray scb intr vec 0x%x ipl%x\n")
276	POPR
277	rei
278
279#if NMBA > 0
280SCBVEC(mba3int):
281	PUSHR; incl _intrcnt+I_MBA3; pushl $3; brb 1f
282SCBVEC(mba2int):
283	PUSHR; incl _intrcnt+I_MBA2; pushl $2; brb 1f
284SCBVEC(mba1int):
285	PUSHR; incl _intrcnt+I_MBA1; pushl $1; brb 1f
286SCBVEC(mba0int):
287	PUSHR; incl _intrcnt+I_MBA0; pushl $0
2881:	calls $1,_mbintr
289	POPR
290	incl	_cnt+V_INTR
291	rei
292#endif
293
294#ifdef DW780
295/*
296 * Registers for the uba handling code
297 */
298#define	rUBANUM	r0
299#define	rUBAHD	r1
300#define	rUVEC	r3
301#define	rUBA	r4
302/* r2,r5 are scratch */
303
304#define	I_UBA	I_UBA0		/* base of UBA interrupt counters */
305
306#if NUBA > 4
307SCBVEC(ua7int):
308	PUSHR; movl $7,rUBANUM; moval _uba_hd+(7*UH_SIZE),rUBAHD; brb 1f
309SCBVEC(ua6int):
310	PUSHR; movl $6,rUBANUM; moval _uba_hd+(6*UH_SIZE),rUBAHD; brb 1f
311SCBVEC(ua5int):
312	PUSHR; movl $5,rUBANUM; moval _uba_hd+(5*UH_SIZE),rUBAHD; brb 1f
313SCBVEC(ua4int):
314	PUSHR; movl $4,rUBANUM; moval _uba_hd+(4*UH_SIZE),rUBAHD; brb 1f
315#endif
316SCBVEC(ua3int):
317	PUSHR; movl $3,rUBANUM; moval _uba_hd+(3*UH_SIZE),rUBAHD; brb 1f
318SCBVEC(ua2int):
319	PUSHR; movl $2,rUBANUM; moval _uba_hd+(2*UH_SIZE),rUBAHD; brb 1f
320SCBVEC(ua1int):
321	PUSHR; movl $1,rUBANUM; moval _uba_hd+(1*UH_SIZE),rUBAHD; brb 1f
322SCBVEC(ua0int):
323	PUSHR; movl $0,rUBANUM; moval _uba_hd+(0*UH_SIZE),rUBAHD;
3241:
325	mfpr	$IPL,r2				/* r2 = mfpr(IPL); */
326	movl	UH_UBA(rUBAHD),rUBA		/* uba = uhp->uh_uba; */
327	movl	UBA_BRRVR-0x14*4(rUBA)[r2],rUVEC
328					/* uvec = uba->uba_brrvr[r2-0x14] */
329ubanorm:
330	bleq	ubaerror
331	addl2	UH_VEC(rUBAHD),rUVEC		/* uvec += uh->uh_vec */
332	bicl3	$3,(rUVEC),r1
333	jmp	2(r1)				/* 2 skips ``pushr $0x3f'' */
334ubaerror:
335	PUSHR; calls $0,_ubaerror; POPR		/* ubaerror r/w's r0-r5 */
336	tstl rUVEC; jneq ubanorm		/* rUVEC contains result */
337	incl _intrcnt+I_UBA[rUBANUM]
338	incl	_cnt+V_INTR
339	POPR
340	rei
341#endif
342SCBVEC(cnrint):
343	PUSHR; calls $0,_cnrint; POPR
344	incl _cnt+V_INTR
345	incl _intrcnt+I_CNR
346	rei
347SCBVEC(cnxint):
348	PUSHR; calls $0,_cnxint; POPR
349	incl _cnt+V_INTR
350	incl _intrcnt+I_CNX
351	rei
352SCBVEC(hardclock):
353	PUSHR
354	mtpr $ICCS_RUN|ICCS_IE|ICCS_INT|ICCS_ERR,$ICCS
355#if NPS > 0
356	pushl	4+6*4(sp); pushl 4+6*4(sp);
357	calls	$2,_psextsync
358#endif
359	pushl 4+6*4(sp); pushl 4+6*4(sp);
360	calls $2,_hardclock			# hardclock(pc,psl)
361	POPR;
362	incl	_cnt+V_INTR
363	incl	_intrcnt+I_CLOCK
364	rei
365SCBVEC(softclock):
366	PUSHR
367	pushl	4+6*4(sp); pushl 4+6*4(sp);
368	calls	$2,_softclock			# softclock(pc,psl)
369	POPR;
370	incl	_cnt+V_SOFT
371	rei
372
373#include "../net/netisr.h"
374	.globl	_netisr
375SCBVEC(netintr):
376	PUSHR
377#include "imp.h"
378#if NIMP > 0
379	bbcc	$NETISR_IMP,_netisr,1f; calls $0,_impintr; 1:
380#endif
381#ifdef INET
382	bbcc	$NETISR_IP,_netisr,1f; calls $0,_ipintr; 1:
383#endif
384#ifdef NS
385	bbcc	$NETISR_NS,_netisr,1f; calls $0,_nsintr; 1:
386#endif
387#ifdef ISO
388	bbcc	$NETISR_ISO,_netisr,1f; calls $0,_clnlintr; 1:
389#endif
390#ifdef ISO
391	bbcc	$NETISR_CCITT,_netisr,1f; calls $0,_hdintr; 1:
392#endif
393	POPR
394	incl	_cnt+V_SOFT
395	rei
396
397SCBVEC(consdin):
398	PUSHR;
399	incl	_intrcnt+I_TUR
400	casel	_cpu,$VAX_750,$VAX_8200
4010:
402	.word	5f-0b		# 2 is VAX_750
403	.word	3f-0b		# 3 is VAX_730
404	.word	6f-0b		# 4 is VAX_8600
405	.word	7f-0b		# 5 is VAX_8200
406	halt
4075:
408#if defined(VAX750) && !defined(MRSP)
409	jsb	tudma
410#endif
4113:
412#if defined(VAX750) || defined(VAX730)
413	calls	$0,_turintr
414	brb	2f
415#else
416	halt
417#endif
4187:
419#if VAX8200
420	calls	$0,_rx50intr
421	brb	2f
422#else
423	halt
424#endif
4256:
426#if VAX8600
427	calls	$0,_crlintr
428#else
429	halt
430#endif
4312:
432	POPR
433	incl	_cnt+V_INTR
434	rei
435
436#if defined(VAX750) || defined(VAX730)
437SCBVEC(consdout):
438	PUSHR; calls $0,_tuxintr; POPR
439	incl _cnt+V_INTR
440	incl _intrcnt+I_TUX
441	rei
442#else
443SCBVEC(consdout):
444	halt
445#endif
446
447#if NDZ > 0
448/*
449 * DZ pseudo dma routine:
450 *	r0 - controller number
451 */
452	.align	1
453	.globl	dzdma
454dzdma:
455	mull2	$8*20,r0
456	movab	_dzpdma(r0),r3		# pdma structure base
457					# for this controller
458dzploop:
459	movl	r3,r0
460	movl	(r0)+,r1		# device register address
461	movzbl	1(r1),r2		# get line number
462	bitb	$0x80,r2		# TRDY on?
463	beql	dzprei			# no
464	bicb2	$0xf8,r2		# clear garbage bits
465	mull2	$20,r2
466	addl2	r2,r0			# point at line's pdma structure
467	movl	(r0)+,r2		# p_mem
468	cmpl	r2,(r0)+		# p_mem < p_end ?
469	bgequ	dzpcall			# no, go call dzxint
470	movb	(r2)+,6(r1)		# dztbuf = *p_mem++
471	movl	r2,-8(r0)
472	brb 	dzploop			# check for another line
473dzprei:
474	POPR
475	incl	_cnt+V_PDMA
476	rei
477
478dzpcall:
479	pushl	r3
480	pushl	(r0)+			# push tty address
481	calls	$1,*(r0)		# call interrupt rtn
482	movl	(sp)+,r3
483	brb 	dzploop			# check for another line
484#endif
485
486#if NDP > 0
487/*
488 * DPV-11 pseudo dma routine:
489 *	r0 - controller number
490 */
491	.align	1
492	.globl	dprdma
493	.globl	dpxdma
494dprdma:
495	mull3	$2*20,r0,r3
496	movab	_dppdma+20(r3),r3	# pdma structure base
497	movl	(r3),r1			# device register address
498	movw	(r1),r2			# get dprcsr
499	bitw	$0x400,r2		# Attention on?
500	bneq	dprcall			# yes
501	bitw	$0x80,r2		# Data Ready?
502	beql	dprcall			# no
503	movl	4(r3),r4
504	cmpl	r4,8(r3)		# p_mem < p_end ?
505	bgequ	dprcall			# no, go call dprint
506	movb	2(r1),(r4)+		# *p_mem++ = dptbuf
507	movl	r4,4(r3)		# put back adjusted count
508					# Since we've been interrupted
509	#bitw	$0x4,4(r1)		# check if we can send
510	#beql	dpprei			# no, return
511	#subl2	$20,r3			# point to send pdma
512	#movl	4(r3),r4		# check if
513	#cmpl	r4,8(r3)		# p_mem < p_end ?
514	#bgequ	dpxcall			# no, go call dpxint
515	#tstw	6(r1)			# get dptdsr, sender starved ?
516	#blss	dpxcall			# yes, go call dpxint
517	#movb	(r4)+,6(r1)		# dptbuf = *p_mem++
518	#movl	r4,4(r3)		# put back adjusted count
519dpprei:
520	POPR
521	incl	_cnt+V_PDMA
522	rei
523dprcall:
524	movw	r2,12(r3)
525dpxcall:
526	pushl	r1			# push csr address
527	pushl	r3			# push pdma address
528	pushl	r0			# push unit number
529	calls	$3,*16(r3)		# call interrupt rtn
530	brb	dpprei
531	.globl	dpxdma
532dpxdma:
533	mull3	$2*20,r0,r3
534	movab	_dppdma(r3),r3		# pdma structure base
535	movl	(r3),r1			# device register address
536dpxcheck:
537	movl	4(r3),r4
538	cmpl	r4,8(r3)		# p_mem < p_end ?
539	bgequ	dpxcall			# no, go call dpxint
540	bitw	$0x4,4(r1)		# ok to send
541	beql	dpxcall			# no, go call dpxint
542	tstw	6(r1)			# get dptdsr, sender starved ?
543	blss	dpxcall			# yes, go call dpxint
544	movb	(r4)+,6(r1)		# dptbuf = *p_mem++
545	movl	r4,4(r3)		# put back adjusted count
546	bitw	$0x4,4(r1)	# check if board has a full tummy
547	bneq	dpprei		# still hungry, don't increment
548	incl	12(r3)		# positive indication we did everything
549	#addl2	$20,r3			# check if input ready
550	#movw	(r1),r2			# get dprcsr
551	#bitw	$0x400,r2		# Attention on?
552	#bneq	dprcall			# yes
553	#bitw	$0x80,r2		# Data Ready?
554	#beql	dpprei			# no, just return
555	#movl	4(r3),r4
556	#cmpl	r4,8(r3)		# p_mem < p_end ?
557	#bgequ	dprcall			# no, go call dprint
558	#movb	2(r1),(r4)+		# dptbuf = *p_mem++
559	#movl	r4,4(r3)		# put back adjusted count
560	brb	dpprei
561#endif
562
563#if NUU > 0 && defined(UUDMA)
564/*
565 * Pseudo DMA routine for tu58 (on DL11)
566 *	r0 - controller number
567 */
568	.align	1
569	.globl	uudma
570uudma:
571	movl	_uudinfo[r0],r2
572	movl	16(r2),r2		# r2 = uuaddr
573	mull3	$48,r0,r3
574	movab	_uu_softc(r3),r5	# r5 = uuc
575
576	cvtwl	2(r2),r1		# c = uuaddr->rdb
577	bbc	$15,r1,1f		# if (c & UUDB_ERROR)
578	movl	$13,16(r5)		#	uuc->tu_state = TUC_RCVERR;
579	rsb				#	let uurintr handle it
5801:
581	tstl	4(r5)			# if (uuc->tu_rcnt) {
582	beql	1f
583	movb	r1,*0(r5)		#	*uuc->tu_rbptr++ = r1
584	incl	(r5)
585	decl	4(r5)			#	if (--uuc->tu_rcnt)
586	beql	2f			#		done
587	tstl	(sp)+
588	POPR				# 	registers saved in ubglue.s
589	rei				# }
5902:
591	cmpl	16(r5),$8		# if (uuc->tu_state != TUS_GETH)
592	beql	2f			# 	let uurintr handle it
5931:
594	rsb
5952:
596	mull2	$14,r0			# sizeof(uudata[ctlr]) = 14
597	movab	_uudata(r0),r4		# data = &uudata[ctlr];
598	cmpb	$1,(r4)			# if (data->pk_flag != TUF_DATA)
599	bneq	1b
600#ifdef notdef
601	/* this is for command packets */
602	beql	1f			# 	r0 = uuc->tu_rbptr
603	movl	(r5),r0
604	brb	2f
6051:					# else
606#endif
607	movl	24(r5),r0		# 	r0 = uuc->tu_addr
6082:
609	movzbl	1(r4),r3		# counter to r3 (data->pk_count)
610	movzwl	(r4),r1			# first word of checksum (=header)
611	mfpr	$IPL,-(sp)		# s = spl5();
612	mtpr	$0x15,$IPL		# to keep disk interrupts out
613	clrw	(r2)			# disable receiver interrupts
6143:	bbc	$7,(r2),3b		# while ((uuaddr->rcs & UUCS_READY)==0);
615	cvtwb	2(r2),(r0)+		# *buffer = uuaddr->rdb & 0xff
616	sobgtr	r3,1f			# continue with next byte ...
617	addw2	2(r2),r1		# unless this was the last (odd count)
618	brb	2f
619
6201:	bbc	$7,(r2),1b		# while ((uuaddr->rcs & UUCS_READY)==0);
621	cvtwb	2(r2),(r0)+		# *buffer = uuaddr->rdb & 0xff
622	addw2	-2(r0),r1		# add to checksum..
6232:
624	adwc	$0,r1			# get the carry
625	sobgtr	r3,3b			# loop while r3 > 0
626/*
627 * We're ready to get the checksum
628 */
6291:	bbc	$7,(r2),1b		# while ((uuaddr->rcs & UUCS_READY)==0);
630	cvtwb	2(r2),12(r4)		# get first (lower) byte
6311:	bbc	$7,(r2),1b
632	cvtwb	2(r2),13(r4)		# ..and second
633	cmpw	12(r4),r1		# is checksum ok?
634	beql	1f
635	movl	$14,16(r5)		# uuc->tu_state = TUS_CHKERR
636	brb	2f			# exit
6371:
638	movl	$11,16(r5)		# uuc->tu_state = TUS_GET (ok)
6392:
640	movw	$0x40,(r2)		# enable receiver interrupts
641	mtpr	(sp)+,$IPL		# splx(s);
642	rsb				# continue processing in uurintr
643#endif
644
645#if defined(VAX750) && !defined(MRSP)
646/*
647 * Pseudo DMA routine for VAX-11/750 console tu58
648 *   	    (without MRSP)
649 */
650	.align	1
651	.globl	tudma
652tudma:
653	movab	_tu,r5			# r5 = tu
654	tstl	4(r5)			# if (tu.tu_rcnt) {
655	beql	3f
656	mfpr	$CSRD,r1		# get data from tu58
657	movb	r1,*0(r5)		#	*tu.tu_rbptr++ = r1
658	incl	(r5)
659	decl	4(r5)			#	if (--tu.tu_rcnt)
660	beql	1f			#		done
661	tstl	(sp)+
662	POPR				# 	registers saved in ubglue.s
663	rei				# 	data handled, done
6641:					# }
665	cmpl	16(r5),$8		# if (tu.tu_state != TUS_GETH)
666	beql	2f			# 	let turintr handle it
6673:
668	rsb
6692:
670	movab	_tudata,r4		# r4 = tudata
671	cmpb	$1,(r4)			# if (tudata.pk_flag != TUF_DATA)
672	bneq	3b			# 	let turintr handle it
6731:					# else
674	movl	24(r5),r1		# get buffer pointer to r1
675	movzbl	1(r4),r3		# counter to r3
676	movzwl	(r4),r0			# first word of checksum (=header)
677	mtpr	$0,$CSRS		# disable receiver interrupts
6783:
679	bsbw	5f			# wait for next byte
680	mfpr	$CSRD,r5
681	movb	r5,(r1)+		# *buffer = rdb
682	sobgtr	r3,1f			# continue with next byte ...
683	mfpr	$CSRD,r2		# unless this was the last (odd count)
684	brb	2f
685
6861:	bsbw	5f			# wait for next byte
687	mfpr	$CSRD,r5
688	movb	r5,(r1)+		# *buffer = rdb
689	movzwl	-2(r1),r2		# get the last word back from memory
6902:
691	addw2	r2,r0			# add to checksum..
692	adwc	$0,r0			# get the carry
693	sobgtr	r3,3b			# loop while r3 > 0
694/*
695 * We're ready to get the checksum.
696 */
697	bsbw	5f
698	movab	_tudata,r4
699	mfpr	$CSRD,r5
700	movb	r5,12(r4)		# get first (lower) byte
701	bsbw	5f
702	mfpr	$CSRD,r5
703	movb	r5,13(r4)		# ..and second
704	movab	_tu,r5
705	cmpw	12(r4),r0		# is checksum ok?
706	beql	1f
707	movl	$14,16(r5)		# tu.tu_state = TUS_CHKERR
708	brb	2f			# exit
7091:
710	movl	$11,16(r5)		# tu.tu_state = TUS_GET
7112:
712	mtpr	$0x40,$CSRS		# enable receiver interrupts
713	rsb				# continue processing in turintr
714/*
715 * Loop until a new byte is ready from
716 * the tu58, make sure we don't loop forever
717 */
7185:
719	movl	$5000,r5		# loop max 5000 times
7201:
721	mfpr	$CSRS,r2
722	bbs	$7,r2,1f
723	sobgtr	r5,1b
724	movab	_tu,r5
725	movl	$13,16(r5)		# return TUS_RCVERR
726	tstl	(sp)+			# and let turintr handle it
7271:
728	rsb
729#endif
730
731/*
732 * BI passive release things.
733 */
734SCBVEC(passiverel):
735	rei				# well that was useless
736
737/*
738 * Stray UNIBUS interrupt catch routines
739 */
740	.data
741	.align	2
742#define	PJ	PUSHR;jsb _Xustray
743	.globl	_catcher
744_catcher:
745	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
746	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
747	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
748	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
749	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
750	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
751	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
752	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
753
754	.globl	_cold
755	.globl	_br
756	.globl	_cvec
757_cold:	.long	1
758_br:	.long	0
759_cvec:	.long	0
760
761	.text
762SCBVEC(ustray):
763	blbc	_cold,1f
764	mfpr	$IPL,r11
765	movl	r11,_br
766	subl3	$_catcher+8,(sp)+,r10
767	ashl	$-1,r10,r10
768	movl	r10,_cvec
769	POPR
770	rei
7711:
772	subl3	$_catcher+8,(sp)+,r0
773	ashl	$-1,r0,-(sp)
774	mfpr	$IPL,-(sp)
775	PRINTF(2, "uba?: stray intr ipl %x vec %o\n")
776	POPR
777	rei
778
779#if VAX630 || VAX650
780/*
781 * Emulation OpCode jump table:
782 *	ONLY GOES FROM 0xf8 (-8) TO 0x3B (59)
783 */
784#define EMUTABLE	0x43
785#define NOEMULATE	.long noemulate
786#define	EMULATE(a)	.long _EM/**/a
787	.globl	_emJUMPtable
788_emJUMPtable:
789/* f8 */	EMULATE(ashp);	EMULATE(cvtlp);	NOEMULATE;	NOEMULATE
790/* fc */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
791/* 00 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
792/* 04 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
793/* 08 */	EMULATE(cvtps);	EMULATE(cvtsp);	NOEMULATE;	EMULATE(crc)
794/* 0c */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
795/* 10 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
796/* 14 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
797/* 18 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
798/* 1c */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
799/* 20 */	EMULATE(addp4);	EMULATE(addp6);	EMULATE(subp4);	EMULATE(subp6)
800/* 24 */	EMULATE(cvtpt);	EMULATE(mulp);	EMULATE(cvttp);	EMULATE(divp)
801/* 28 */	NOEMULATE;	EMULATE(cmpc3);	EMULATE(scanc);	EMULATE(spanc)
802/* 2c */	NOEMULATE;	EMULATE(cmpc5);	EMULATE(movtc);	EMULATE(movtuc)
803/* 30 */	NOEMULATE;	NOEMULATE;	NOEMULATE;	NOEMULATE
804/* 34 */	EMULATE(movp);	EMULATE(cmpp3);	EMULATE(cvtpl);	EMULATE(cmpp4)
805/* 38 */	EMULATE(editpc); EMULATE(matchc); EMULATE(locc); EMULATE(skpc)
806#endif
807
808/*
809 * Trap and fault vector routines
810 */
811#define	TRAP(a)	pushl $T_/**/a; jbr alltraps
812
813/*
814 * Ast delivery (profiling and/or reschedule)
815 */
816SCBVEC(astflt):
817	pushl $0; TRAP(ASTFLT)
818SCBVEC(privinflt):
819	pushl $0; TRAP(PRIVINFLT)
820SCBVEC(xfcflt):
821	pushl $0; TRAP(XFCFLT)
822SCBVEC(resopflt):
823	pushl $0; TRAP(RESOPFLT)
824SCBVEC(resadflt):
825	pushl $0; TRAP(RESADFLT)
826SCBVEC(bptflt):
827	pushl $0; TRAP(BPTFLT)
828SCBVEC(compatflt):
829	TRAP(COMPATFLT);
830SCBVEC(kdbintr):
831	pushl $0; TRAP(KDBTRAP)
832SCBVEC(tracep):
833	pushl $0; TRAP(TRCTRAP)
834SCBVEC(arithtrap):
835	TRAP(ARITHTRAP)
836SCBVEC(protflt):
837	blbs	(sp)+,segflt
838	TRAP(PROTFLT)
839segflt:
840	TRAP(SEGFLT)
841
842/*
843 * The following is called with the stack set up as follows:
844 *
845 *	  (sp):	Opcode
846 *	 4(sp):	Instruction PC
847 *	 8(sp):	Operand 1
848 *	12(sp):	Operand 2
849 *	16(sp):	Operand 3
850 *	20(sp):	Operand 4
851 *	24(sp):	Operand 5
852 *	28(sp):	Operand 6
853 *	32(sp):	Operand 7 (unused)
854 *	36(sp):	Operand 8 (unused)
855 *	40(sp):	Return PC
856 *	44(sp):	Return PSL
857 *	48(sp): TOS before instruction
858 *
859 * Each individual routine is called with the stack set up as follows:
860 *
861 *	  (sp):	Return address of trap handler
862 *	 4(sp):	Opcode (will get return PSL)
863 *	 8(sp):	Instruction PC
864 *	12(sp):	Operand 1
865 *	16(sp):	Operand 2
866 *	20(sp):	Operand 3
867 *	24(sp):	Operand 4
868 *	28(sp):	Operand 5
869 *	32(sp):	Operand 6
870 *	36(sp):	saved register 11
871 *	40(sp):	saved register 10
872 *	44(sp):	Return PC
873 *	48(sp):	Return PSL
874 *	52(sp): TOS before instruction
875 */
876
877SCBVEC(emulate):
878#if VAX630 || VAX650
879	movl	r11,32(sp)		# save register r11 in unused operand
880	movl	r10,36(sp)		# save register r10 in unused operand
881	cvtbl	(sp),r10		# get opcode
882	addl2	$8,r10			# shift negative opcodes
883	subl3	r10,$EMUTABLE,r11	# forget it if opcode is out of range
884	bcs	noemulate
885	movl	_emJUMPtable[r10],r10	# call appropriate emulation routine
886	jsb	(r10)		# routines put return values into regs 0-5
887	movl	32(sp),r11		# restore register r11
888	movl	36(sp),r10		# restore register r10
889	insv	(sp),$0,$4,44(sp)	# and condition codes in Opcode spot
890	addl2	$40,sp			# adjust stack for return
891	rei
892noemulate:
893	addl2	$48,sp			# adjust stack for
894#endif
895	.word	0xffff			# "reserved instruction fault"
896SCBVEC(emulateFPD):
897	.word	0xffff			# "reserved instruction fault"
898SCBVEC(transflt):
899	bitl	$2,(sp)+
900	bnequ	tableflt
901 	jsb	Fastreclaim		# try and avoid pagein
902	TRAP(PAGEFLT)
903tableflt:
904	TRAP(TABLEFLT)
905
906alltraps:
907	mfpr	$USP,-(sp); calls $0,_trap; mtpr (sp)+,$USP
908	incl	_cnt+V_TRAP
909	addl2	$8,sp			# pop type, code
910	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
911	rei
912
913SCBVEC(syscall):
914	pushl	$T_SYSCALL
915	mfpr	$USP,-(sp); calls $0,_syscall; mtpr (sp)+,$USP
916	incl	_cnt+V_SYSCALL
917	addl2	$8,sp			# pop type, code
918	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
919	rei
920
921/*
922 * System page table
923 * Mbmap and Usrptmap are enlarged by CLSIZE entries
924 * as they are managed by resource maps starting with index 1 or CLSIZE.
925 */
926#define	vaddr(x)	((((x)-_Sysmap)/4)*NBPG+0x80000000)
927#define	SYSMAP(mname, vname, npte)			\
928_/**/mname:	.globl	_/**/mname;		\
929	.space	(npte)*4;				\
930	.globl	_/**/vname;			\
931	.set	_/**/vname,vaddr(_/**/mname)
932#define	ADDMAP(npte)	.space	(npte)*4
933
934	.data
935	.align	2
936	SYSMAP(Sysmap	,Sysbase	,SYSPTSIZE	)
937	SYSMAP(Forkmap	,forkutl	,UPAGES		)
938	SYSMAP(Xswapmap	,xswaputl	,UPAGES		)
939	SYSMAP(Xswap2map,xswap2utl	,UPAGES		)
940	SYSMAP(Swapmap	,swaputl	,UPAGES		)
941	SYSMAP(Pushmap	,pushutl	,UPAGES		)
942	SYSMAP(Vfmap	,vfutl		,UPAGES		)
943	SYSMAP(CMAP1	,CADDR1		,1		)
944	SYSMAP(CMAP2	,CADDR2		,1		)
945	SYSMAP(mmap	,vmmap		,1		)
946	SYSMAP(alignmap	,alignutl	,1		)	/* XXX */
947	SYSMAP(msgbufmap,msgbuf		,MSGBUFPTECNT	)
948	SYSMAP(Mbmap	,mbutl		,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE )
949#ifdef MFS
950#include "../ufs/mfsiom.h"
951	/*
952	 * Used by the mfs_doio() routine for physical I/O
953	 */
954	SYSMAP(Mfsiomap	,mfsiobuf	,MFS_MAPREG )
955#endif /* MFS */
956#ifdef NFS
957#include "../nfs/nfsiom.h"
958	/*
959	 * Used by the nfs_doio() routine for physical I/O
960	 */
961	SYSMAP(Nfsiomap	,nfsiobuf	,NFS_MAPREG )
962#endif /* NFS */
963	/*
964	 * This is the map used by the kernel memory allocator.
965	 * It is expanded as necessary by the special features
966	 * that use it.
967	 *
968	 * XXX: NEED way to compute kmem size from maxusers,
969	 * device complement
970	 */
971	SYSMAP(kmempt	,kmembase	,NKMEMCLUSTERS*CLSIZE )
972#ifdef	SYSVSHM
973				ADDMAP(	SHMMAXPGS	)
974#endif
975#ifdef	GPROF
976				ADDMAP( 600*CLSIZE	)
977#endif
978	SYSMAP(ekmempt	,kmemlimit	,0		)
979
980	SYSMAP(UMBAbeg	,umbabeg	,0		)
981	SYSMAP(Nexmap	,nexus		,16*MAXNNEXUS	)
982#ifdef QBA
983#if (QBAPAGES+UBAIOPAGES) > (UBAPAGES+UBAIOPAGES)*NUBA
984	SYSMAP(UMEMmap	,umem		,(QBAPAGES+UBAIOPAGES) )
985#else
986	SYSMAP(UMEMmap	,umem		,(UBAPAGES+UBAIOPAGES)*NUBA )
987#endif
988#else /* QBA */
989	SYSMAP(UMEMmap	,umem		,(UBAPAGES+UBAIOPAGES)*NUBA )
990#endif /* QBA */
991#if VAX8600
992	SYSMAP(Ioamap	,ioa		,MAXNIOA*IOAMAPSIZ/NBPG	)
993#endif
994#if VAX8200 || VAX630
995	SYSMAP(Clockmap	,ka630clock	,1		)
996#endif
997#if VAX8200
998	/* alas, the clocks on the 8200 and 630 are not quite identical */
999	/* they could be shared for now, but this seemed cleaner */
1000	.globl _ka820clock; .set _ka820clock,_ka630clock
1001	SYSMAP(Ka820map	,ka820port	,1		)
1002	SYSMAP(RX50map	,rx50device	,1		)
1003#ifdef notyet
1004	SYSMAP(BRAMmap	,ka820bootram	,KA820_BRPAGES	)
1005	SYSMAP(EEPROMmap,ka820eeprom	,KA820_EEPAGES	)
1006#endif
1007#endif
1008#if VAX630
1009	SYSMAP(Ka630map	,ka630cpu	,1		)
1010#endif
1011#if VAX650
1012 	SYSMAP(KA650MERRmap	,ka650merr	,1		)
1013 	SYSMAP(KA650CBDmap	,ka650cbd	,1		)
1014 	SYSMAP(KA650SSCmap	,ka650ssc	,3		)
1015 	SYSMAP(KA650IPCRmap	,ka650ipcr	,1		)
1016 	SYSMAP(KA650CACHEmap	,ka650cache	,KA650_CACHESIZE/NBPG )
1017#endif
1018#ifdef QBA
1019	/*
1020	 * qvss and qdss don't coexist - one map will suffice
1021	 * for either. qvss is 256K each and qdss is 64K each.
1022	 */
1023#include "qv.h"
1024#include "qd.h"
1025#if NQV > 0 || NQD > 0
1026	SYSMAP(QVmap	,qvmem		,((512*NQV)+(128*NQD)))
1027#endif
1028#endif
1029	SYSMAP(UMBAend	,umbaend	,0		)
1030
1031	SYSMAP(Usrptmap	,usrpt		,USRPTSIZE+CLSIZE )
1032
1033eSysmap:
1034	.globl	_Syssize
1035	.set	_Syssize,(eSysmap-_Sysmap)/4
1036	.text
1037
1038/*
1039 * Initialization
1040 *
1041 * ipl 0x1f; mapen 0; scbb, pcbb, sbr, slr, isp, ksp not set
1042 */
1043	.data
1044	.globl	_cpu
1045_cpu:	.long	0
1046	.text
1047	.globl	start
1048start:
1049	.word	0
1050	mtpr	$0,$ICCS
1051/* set system control block base and system page table params */
1052	mtpr	$_scb-0x80000000,$SCBB
1053	mtpr	$_Sysmap-0x80000000,$SBR
1054	mtpr	$_Syssize,$SLR
1055/* double map the kernel into the virtual user addresses of phys mem */
1056	mtpr	$_Sysmap,$P0BR
1057	mtpr	$_Syssize,$P0LR
1058/* set ISP and get cpu type */
1059	movl	$_intstack+NISP*NBPG,sp
1060	mfpr	$SID,r0
1061	movab	_cpu,r1
1062	extzv	$24,$8,r0,(r1)
1063/* init RPB */
1064	movab	_rpb,r0
1065	movl	r0,(r0)+			# rp_selfref
1066	movab	_doadump,r1
1067	movl	r1,(r0)+			# rp_dumprout
1068	movl	$0x1f,r2
1069	clrl	r3
10701:	addl2	(r1)+,r3; sobgtr r2,1b
1071	movl	r3,(r0)+			# rp_chksum
1072/* count up memory; _physmem contains limit */
1073	clrl	r7
1074	ashl	$PGSHIFT,_physmem,r8
1075	decl	r8
10761:	pushl	$4; pushl r7; calls $2,_badaddr; tstl r0; bneq 9f
1077	acbl	r8,$64*1024,r7,1b
10789:
1079#if  VAX630 || VAX650
1080/* reserve area at top of memory for processor specific use */
1081	cmpb	_cpu,$VAX_630
1082	beql	1f
1083	cmpb	_cpu,$VAX_650
1084	bneq	2f
1085	subl2	$32768,r7	# space for Qbus map registers
1086	brb	2f
10871:
1088	subl2   $4096,r7	# space for console scratchpad
10892:
1090#endif
1091/* clear memory from kernel bss and pages for proc 0 u. and page table */
1092	movab	_edata,r6; bicl2 $SYSTEM,r6
1093	movab	_end,r5; bicl2 $SYSTEM,r5
1094#ifdef KADB
1095	subl2	$4,r5
10961:	clrl	(r6); acbl r5,$4,r6,1b		# clear just bss
1097	addl2	$4,r5
1098	bbc	$6,r11,0f			# check RB_KDB
1099	bicl3	$SYSTEM,r9,r5			# skip symbol & string tables
1100	bicl3	$SYSTEM,r9,r6			# r9 obtained from boot
1101#endif
11020:	bisl3	$SYSTEM,r5,r9			# convert to virtual address
1103	addl2	$NBPG-1,r9			# roundup to next page
1104	addl2	$(UPAGES*NBPG)+NBPG+NBPG,r5
11051:	clrq	(r6); acbl r5,$8,r6,1b
1106/* trap() and syscall() save r0-r11 in the entry mask (per ../h/reg.h) */
1107/* panic() is convenient place to save all for debugging */
1108	bisw2	$0x0fff,_trap
1109	bisw2	$0x0fff,_syscall
1110	bisw2	$0x0fff,_panic
1111	calls	$0,_fixctlrmask
1112/* initialize system page table: uba vectors and int stack writeable */
1113	clrl	r2
1114	movab	eintstack,r1; bbcc $31,r1,0f; 0: ashl $-PGSHIFT,r1,r1
11151:	bisl3	$PG_V|PG_KW,r2,_Sysmap[r2]; aoblss r1,r2,1b
1116/*
1117 * make rpb read-only as red zone for interrupt stack
1118 * (scb(s) and UNIvec are write-protected later)
1119 */
1120	bicl2	$PG_PROT,_rpbmap
1121	bisl2	$PG_KR,_rpbmap
1122/* make kernel text space read-only */
1123	movab	_etext+NBPG-1,r1; bbcc $31,r1,0f; 0: ashl $-PGSHIFT,r1,r1
11241:	bisl3	$PG_V|PG_URKR,r2,_Sysmap[r2]; aoblss r1,r2,1b
1125/* make kernel data, bss, read-write */
1126	bicl3	$SYSTEM,r9,r1; ashl $-PGSHIFT,r1,r1
11271:	bisl3	$PG_V|PG_KW,r2,_Sysmap[r2]; aoblss r1,r2,1b
1128/* now go to mapped mode */
1129	mtpr	$0,$TBIA; mtpr $1,$MAPEN; jmp *$0f; 0:
1130/* init mem sizes */
1131	ashl	$-PGSHIFT,r7,_physmem
1132/* setup context for proc[0] == Scheduler */
1133	bicl3	$SYSTEM|(NBPG-1),r9,r6	# make phys, page boundary
1134/* setup page table for proc[0] */
1135	ashl	$-PGSHIFT,r6,r3			# r3 = btoc(r6)
1136	bisl3	$PG_V|PG_KW,r3,_Usrptmap	# init first upt entry
1137	incl	r3
1138	movab	_usrpt,r0
1139	mtpr	r0,$TBIS
1140/* init p0br, p0lr */
1141	mtpr	r0,$P0BR
1142	mtpr	$0,$P0LR
1143/* init p1br, p1lr */
1144	movab	NBPG(r0),r0
1145	movl	$0x200000-UPAGES,r1
1146	mtpr	r1,$P1LR
1147	mnegl	r1,r1
1148	moval	-4*UPAGES(r0)[r1],r2
1149	mtpr	r2,$P1BR
1150/* setup mapping for UPAGES of _u */
1151	movl	$UPAGES,r2; movab _u+NBPG*UPAGES,r1; addl2 $UPAGES,r3; jbr 2f
11521:	decl	r3
1153	moval	-NBPG(r1),r1;
1154	bisl3	$PG_V|PG_URKW,r3,-(r0)
1155	mtpr	r1,$TBIS
11562:	sobgeq	r2,1b
1157/* initialize (slightly) the pcb */
1158	movab	UPAGES*NBPG(r1),PCB_KSP(r1)
1159	mnegl	$1,PCB_ESP(r1)
1160	mnegl	$1,PCB_SSP(r1)
1161	movl	r1,PCB_USP(r1)
1162	mfpr	$P0BR,PCB_P0BR(r1)
1163	mfpr	$P0LR,PCB_P0LR(r1)
1164	movb	$4,PCB_P0LR+3(r1)		# disable ast
1165	mfpr	$P1BR,PCB_P1BR(r1)
1166	mfpr	$P1LR,PCB_P1LR(r1)
1167	movl	$CLSIZE,PCB_SZPT(r1)		# init u.u_pcb.pcb_szpt
1168	movl	r9,PCB_R9(r1)
1169	movl	r10,PCB_R10(r1)
1170	movl	r11,PCB_R11(r1)
1171	movab	1f,PCB_PC(r1)			# initial pc
1172	clrl	PCB_PSL(r1)			# mode(k,k), ipl=0
1173	ashl	$PGSHIFT,r3,r3
1174	mtpr	r3,$PCBB			# first pcbb
1175/* set regs, p0br, p0lr, p1br, p1lr, astlvl, ksp and change to kernel mode */
1176	ldpctx
1177	rei
1178/* put signal trampoline code in u. area */
11791:	movab	_u,r0
1180	movc3	$19,sigcode,PCB_SIGC(r0)
1181/* save boot device in global _bootdev */
1182	movl	r10,_bootdev
1183/* save reboot flags in global _boothowto */
1184	movl	r11,_boothowto
1185#ifdef KADB
1186/* save end of symbol & string table in global _bootesym */
1187	subl3	$NBPG-1,r9,_bootesym
1188#endif
1189/* calculate firstaddr, and call main() */
1190	bicl3	$SYSTEM,r9,r0; ashl $-PGSHIFT,r0,-(sp)
1191	addl2	$UPAGES+1,(sp); calls $1,_main
1192/* proc[1] == /etc/init now running here; run icode */
1193	pushl	$PSL_CURMOD|PSL_PRVMOD; pushl $0; rei
1194
1195/* signal trampoline code: it is known that this code takes exactly 19 bytes */
1196/* in ../vax/pcb.h and in the movc3 above */
1197sigcode:
1198	calls	$4,8(pc)	# params pushed by sendsig
1199	movl	sp,ap		# calls frame built by sendsig
1200	chmk	$SYS_sigreturn	# cleanup mask and onsigstack
1201	halt			# sigreturn() does not return!
1202	.word	0x3f		# registers 0-5
1203	callg	(ap),*16(ap)	# call the signal handler
1204	ret			# return to code above
1205
1206	.globl	_icode
1207	.globl	_initflags
1208	.globl	_szicode
1209/*
1210 * Icode is copied out to process 1 to exec /etc/init.
1211 * If the exec fails, process 1 exits.
1212 */
1213_icode:
1214	pushab	b`argv-l0(pc)
1215l0:	pushab	b`init-l1(pc)
1216l1:	pushl	$2
1217	movl	sp,ap
1218	chmk	$SYS_execv
1219	pushl	r0
1220	chmk	$SYS_exit
1221
1222init:	.asciz	"/sbin/init"
1223	.align	2
1224_initflags:
1225	.long	0
1226argv:	.long	init+6-_icode
1227	.long	_initflags-_icode
1228	.long	0
1229_szicode:
1230	.long	_szicode-_icode
1231
1232/*
1233 * Primitives
1234 */
1235
1236#ifdef GPROF
1237#define	ENTRY(name, regs) \
1238	.globl _/**/name; .align 1; _/**/name: .word regs; jsb mcount
1239#define	JSBENTRY(name, regs) \
1240	.globl _/**/name; _/**/name: \
1241	movl fp,-(sp); movab -12(sp),fp; pushr $(regs); jsb mcount; \
1242	popr $(regs); movl (sp)+,fp
1243#else
1244#define	ENTRY(name, regs) \
1245	.globl _/**/name; .align 1; _/**/name: .word regs
1246#define	JSBENTRY(name, regs) \
1247	.globl _/**/name; _/**/name:
1248#endif GPROF
1249#define R0 0x01
1250#define R1 0x02
1251#define R2 0x04
1252#define R3 0x08
1253#define R4 0x10
1254#define R5 0x20
1255#define R6 0x40
1256
1257/*
1258 * badaddr(addr, len)
1259 *	see if access addr with a len type instruction causes a machine check
1260 *	len is length of access (1=byte, 2=short, 4=long)
1261 */
1262	.globl	_badaddr
1263_badaddr:
1264	.word	0
1265	movl	$1,r0
1266	mfpr	$IPL,r1
1267	mtpr	$HIGH,$IPL
1268	movl	4(ap),r3
1269	movl	8(ap),r4
1270	movab	2f,nofault		# jump to 2f on machcheck
1271	bbc	$0,r4,1f; tstb	(r3)
12721:	bbc	$1,r4,1f; tstw	(r3)
12731:	bbc	$2,r4,1f; tstl	(r3)
12741:	clrl	r0			# made it w/o machine checks
12752:	clrl	nofault
1276	mtpr	r1,$IPL
1277	ret
1278
1279/*
1280 * update profiling information for the user
1281 * addupc(pc, &u.u_prof, ticks)
1282 */
1283ENTRY(addupc, 0)
1284	movl	8(ap),r2		# &u.u_prof
1285	subl3	8(r2),4(ap),r0		# corrected pc
1286	blss	9f
1287	extzv	$1,$31,r0,r0		# logical right shift
1288	extzv	$1,$31,12(r2),r1	# ditto for scale
1289	emul	r1,r0,$0,r0
1290	ashq	$-14,r0,r0
1291	tstl	r1
1292	bneq	9f
1293	bicl2	$1,r0
1294	cmpl	r0,4(r2)		# length
1295	bgequ	9f
1296	addl2	(r2),r0			# base
1297	probew	$3,$2,(r0)
1298	beql	8f
1299	addw2	12(ap),(r0)
13009:
1301	ret
13028:
1303	clrl	12(r2)
1304	ret
1305
1306/*
1307 * Copy a null terminated string from the user address space into
1308 * the kernel address space.
1309 *
1310 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
1311 */
1312ENTRY(copyinstr, R6)
1313	movl	12(ap),r6		# r6 = max length
1314	jlss	8f
1315	movl	4(ap),r1		# r1 = user address
1316	bicl3	$~(NBPG*CLSIZE-1),r1,r2	# r2 = bytes on first page
1317	subl3	r2,$NBPG*CLSIZE,r2
1318	movl	8(ap),r3		# r3 = kernel address
13191:
1320	cmpl	r6,r2			# r2 = min(bytes on page, length left);
1321	jgeq	2f
1322	movl	r6,r2
13232:
1324	prober	$3,r2,(r1)		# bytes accessible?
1325	jeql	8f
1326	subl2	r2,r6			# update bytes left count
1327#ifdef NOSUBSINST
1328	# fake the locc instr. for processors that don't have it
1329	movl	r2,r0
13306:
1331	tstb	(r1)+
1332	jeql	5f
1333	sobgtr	r0,6b
1334	jbr	7f
13355:
1336	decl	r1
1337	jbr	3f
13387:
1339#else
1340	locc	$0,r2,(r1)		# null byte found?
1341	jneq	3f
1342#endif
1343	subl2	r2,r1			# back up pointer updated by `locc'
1344	movc3	r2,(r1),(r3)		# copy in next piece
1345	movl	$(NBPG*CLSIZE),r2	# check next page
1346	tstl	r6			# run out of space?
1347	jneq	1b
1348	movl	$ENAMETOOLONG,r0	# set error code and return
1349	jbr	9f
13503:
1351	tstl	16(ap)			# return length?
1352	beql	4f
1353	subl3	r6,12(ap),r6		# actual len = maxlen - unused pages
1354	subl2	r0,r6			#	- unused on this page
1355	addl3	$1,r6,*16(ap)		#	+ the null byte
13564:
1357	subl2	r0,r2			# r2 = number of bytes to move
1358	subl2	r2,r1			# back up pointer updated by `locc'
1359	incl	r2			# copy null byte as well
1360	movc3	r2,(r1),(r3)		# copy in last piece
1361	clrl	r0			# redundant
1362	ret
13638:
1364	movl	$EFAULT,r0
13659:
1366	tstl	16(ap)
1367	beql	1f
1368	subl3	r6,12(ap),*16(ap)
13691:
1370	ret
1371
1372/*
1373 * Copy a null terminated string from the kernel
1374 * address space to the user address space.
1375 *
1376 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1377 */
1378ENTRY(copyoutstr, R6)
1379	movl	12(ap),r6		# r6 = max length
1380	jlss	8b
1381	movl	4(ap),r1		# r1 = kernel address
1382	movl	8(ap),r3		# r3 = user address
1383	bicl3	$~(NBPG*CLSIZE-1),r3,r2	# r2 = bytes on first page
1384	subl3	r2,$NBPG*CLSIZE,r2
13851:
1386	cmpl	r6,r2			# r2 = min(bytes on page, length left);
1387	jgeq	2f
1388	movl	r6,r2
13892:
1390	probew	$3,r2,(r3)		# bytes accessible?
1391	jeql	8b
1392	subl2	r2,r6			# update bytes left count
1393#ifdef NOSUBSINST
1394	# fake the locc instr. for processors that don't have it
1395	movl	r2,r0
13966:
1397	tstb	(r1)+
1398	jeql	5f
1399	sobgtr	r0,6b
1400	jbr	7f
14015:
1402	decl	r1
1403	jbr	3b
14047:
1405#else
1406	locc	$0,r2,(r1)		# null byte found?
1407	jneq	3b
1408#endif
1409	subl2	r2,r1			# back up pointer updated by `locc'
1410	movc3	r2,(r1),(r3)		# copy in next piece
1411	movl	$(NBPG*CLSIZE),r2	# check next page
1412	tstl	r6			# run out of space?
1413	jneq	1b
1414	movl	$ENAMETOOLONG,r0	# set error code and return
1415	jbr	9b
1416
1417/*
1418 * Copy a null terminated string from one point to another in
1419 * the kernel address space.
1420 *
1421 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1422 */
1423ENTRY(copystr, R6)
1424	movl	12(ap),r6		# r6 = max length
1425	jlss	8b
1426	movl	4(ap),r1		# r1 = src address
1427	movl	8(ap),r3		# r3 = dest address
14281:
1429	movzwl	$65535,r2		# r2 = bytes in first chunk
1430	cmpl	r6,r2			# r2 = min(bytes in chunk, length left);
1431	jgeq	2f
1432	movl	r6,r2
14332:
1434	subl2	r2,r6			# update bytes left count
1435#ifdef NOSUBSINST
1436	# fake the locc instr. for processors that don't have it
1437	movl	r2,r0
14386:
1439	tstb	(r1)+
1440	jeql	5f
1441	sobgtr	r0,6b
1442	jbr	7f
14435:
1444	decl	r1
1445	jbr	3b
14467:
1447#else
1448	locc	$0,r2,(r1)		# null byte found?
1449	jneq	3b
1450#endif
1451	subl2	r2,r1			# back up pointer updated by `locc'
1452	movc3	r2,(r1),(r3)		# copy in next piece
1453	tstl	r6			# run out of space?
1454	jneq	1b
1455	movl	$ENAMETOOLONG,r0	# set error code and return
1456	jbr	9b
1457
1458/*
1459 * Copy specified amount of data from user space into the kernel
1460 * Copyin(from, to, len)
1461 *	r1 == from (user source address)
1462 *	r3 == to (kernel destination address)
1463 *	r5 == length
1464 */
1465	.align	1
1466JSBENTRY(Copyin, R1|R3|R5)
1467	cmpl	r5,$(NBPG*CLSIZE)	# probing one page or less ?
1468	bgtru	1f			# no
1469	prober	$3,r5,(r1)		# bytes accessible ?
1470	beql	ersb			# no
1471	movc3	r5,(r1),(r3)
1472/*	clrl	r0			# redundant */
1473	rsb
14741:
1475	blss	ersb			# negative length?
1476	pushl	r6			# r6 = length
1477	movl	r5,r6
1478	bicl3	$~(NBPG*CLSIZE-1),r1,r0	# r0 = bytes on first page
1479	subl3	r0,$(NBPG*CLSIZE),r0
1480	addl2	$(NBPG*CLSIZE),r0	# plus one additional full page
1481	jbr	2f
1482
1483ciloop:
1484	movc3	r0,(r1),(r3)
1485	movl	$(2*NBPG*CLSIZE),r0	# next amount to move
14862:
1487	cmpl	r0,r6
1488	bleq	3f
1489	movl	r6,r0
14903:
1491	prober	$3,r0,(r1)		# bytes accessible ?
1492	beql	ersb1			# no
1493	subl2	r0,r6			# last move?
1494	bneq	ciloop			# no
1495
1496	movc3	r0,(r1),(r3)
1497/*	clrl	r0			# redundant */
1498	movl	(sp)+,r6		# restore r6
1499	rsb
1500
1501ersb1:
1502	movl	(sp)+,r6		# restore r6
1503ersb:
1504	movl	$EFAULT,r0
1505	rsb
1506
1507/*
1508 * Copy specified amount of data from kernel to the user space
1509 * Copyout(from, to, len)
1510 *	r1 == from (kernel source address)
1511 *	r3 == to (user destination address)
1512 *	r5 == length
1513 */
1514	.align	1
1515JSBENTRY(Copyout, R1|R3|R5)
1516	cmpl	r5,$(NBPG*CLSIZE)	# moving one page or less ?
1517	bgtru	1f			# no
1518	probew	$3,r5,(r3)		# bytes writeable?
1519	beql	ersb			# no
1520	movc3	r5,(r1),(r3)
1521/*	clrl	r0			# redundant */
1522	rsb
15231:
1524	blss	ersb			# negative length?
1525	pushl	r6			# r6 = length
1526	movl	r5,r6
1527	bicl3	$~(NBPG*CLSIZE-1),r3,r0	# r0 = bytes on first page
1528	subl3	r0,$(NBPG*CLSIZE),r0
1529	addl2	$(NBPG*CLSIZE),r0	# plus one additional full page
1530	jbr	2f
1531
1532coloop:
1533	movc3	r0,(r1),(r3)
1534	movl	$(2*NBPG*CLSIZE),r0	# next amount to move
15352:
1536	cmpl	r0,r6
1537	bleq	3f
1538	movl	r6,r0
15393:
1540	probew	$3,r0,(r3)		# bytes writeable?
1541	beql	ersb1			# no
1542	subl2	r0,r6			# last move?
1543	bneq	coloop			# no
1544
1545	movc3	r0,(r1),(r3)
1546/*	clrl	r0			# redundant */
1547	movl	(sp)+,r6		# restore r6
1548	rsb
1549
1550/*
1551 * savectx is like setjmp but saves all registers.
1552 * Called before swapping out the u. area, restored by resume()
1553 * below.
1554 */
1555#define PCLOC 16	/* location of pc in calls frame */
1556#define APLOC 8		/* location of ap,fp in calls frame */
1557
1558ENTRY(savectx, 0)
1559	movl	4(ap),r0
1560	movq	r6,(r0)+
1561	movq	r8,(r0)+
1562	movq	r10,(r0)+
1563	movq	APLOC(fp),(r0)+	# save ap, fp
1564	addl3	$8,ap,(r0)+	# save sp
1565	movl	PCLOC(fp),(r0)	# save pc
1566	clrl	r0
1567	ret
1568
1569#ifdef KADB
1570/*
1571 * C library -- reset, setexit
1572 *
1573 *	reset(x)
1574 * will generate a "return" from
1575 * the last call to
1576 *	setexit()
1577 * by restoring r6 - r12, ap, fp
1578 * and doing a return.
1579 * The returned value is x; on the original
1580 * call the returned value is 0.
1581 */
1582ENTRY(setexit, 0)
1583	movab	setsav,r0
1584	movq	r6,(r0)+
1585	movq	r8,(r0)+
1586	movq	r10,(r0)+
1587	movq	8(fp),(r0)+		# ap, fp
1588	movab	4(ap),(r0)+		# sp
1589	movl	16(fp),(r0)		# pc
1590	clrl	r0
1591	ret
1592
1593ENTRY(reset, 0)
1594	movl	4(ap),r0	# returned value
1595	movab	setsav,r1
1596	movq	(r1)+,r6
1597	movq	(r1)+,r8
1598	movq	(r1)+,r10
1599	movq	(r1)+,r12
1600	movl	(r1)+,sp
1601	jmp 	*(r1)
1602
1603	.data
1604	.align  2
1605setsav:	.space	10*4
1606	.text
1607#endif
1608
1609	.globl	_whichqs
1610	.globl	_qs
1611	.globl	_cnt
1612
1613	.globl	_noproc
1614	.comm	_noproc,4
1615	.globl	_runrun
1616	.comm	_runrun,4
1617
1618/*
1619 * The following primitives use the fancy VAX instructions
1620 * much like VMS does.  _whichqs tells which of the 32 queues _qs
1621 * have processes in them.  Setrq puts processes into queues, Remrq
1622 * removes them from queues.  The running process is on no queue,
1623 * other processes are on a queue related to p->p_pri, divided by 4
1624 * actually to shrink the 0-127 range of priorities into the 32 available
1625 * queues.
1626 */
1627
1628/*
1629 * Setrq(p), using fancy VAX instructions.
1630 *
1631 * Call should be made at splclock(), and p->p_stat should be SRUN
1632 */
1633	.align	1
1634JSBENTRY(Setrq, R0)
1635	tstl	P_RLINK(r0)		## firewall: p->p_rlink must be 0
1636	beql	set1			##
1637	pushab	set3			##
1638	calls	$1,_panic		##
1639set1:
1640	movzbl	P_PRI(r0),r1		# put on queue which is p->p_pri / 4
1641	ashl	$-2,r1,r1
1642	movaq	_qs[r1],r2
1643	insque	(r0),*4(r2)		# at end of queue
1644	bbss	r1,_whichqs,set2	# mark queue non-empty
1645set2:
1646	rsb
1647
1648set3:	.asciz	"setrq"
1649
1650/*
1651 * Remrq(p), using fancy VAX instructions
1652 *
1653 * Call should be made at splclock().
1654 */
1655	.align	1
1656JSBENTRY(Remrq, R0)
1657	movzbl	P_PRI(r0),r1
1658	ashl	$-2,r1,r1
1659	bbsc	r1,_whichqs,rem1
1660	pushab	rem3			# it wasn't recorded to be on its q
1661	calls	$1,_panic
1662rem1:
1663	remque	(r0),r2
1664	beql	rem2
1665	bbss	r1,_whichqs,rem2
1666rem2:
1667	clrl	P_RLINK(r0)		## for firewall checking
1668	rsb
1669
1670rem3:	.asciz	"remrq"
1671
1672/*
1673 * Masterpaddr is the p->p_addr of the running process on the master
1674 * processor.  When a multiprocessor system, the slave processors will have
1675 * an array of slavepaddr's.
1676 */
1677	.globl	_masterpaddr
1678	.data
1679_masterpaddr:
1680	.long	0
1681
1682	.text
1683sw0:	.asciz	"swtch"
1684
1685/*
1686 * When no processes are on the runq, Swtch branches to idle
1687 * to wait for something to come ready.
1688 */
1689	.globl	Idle
1690Idle: idle:
1691	movl	$1,_noproc
1692	mtpr	$0,$IPL			# must allow interrupts here
16931:
1694	tstl	_whichqs		# look for non-empty queue
1695	bneq	sw1
1696	brb	1b
1697
1698badsw:	pushab	sw0
1699	calls	$1,_panic
1700	/*NOTREACHED*/
1701
1702/*
1703 * Swtch(), using fancy VAX instructions
1704 */
1705	.align	1
1706JSBENTRY(Swtch, 0)
1707	incl	_cnt+V_SWTCH
1708sw1:	ffs	$0,$32,_whichqs,r0	# look for non-empty queue
1709	beql	idle			# if none, idle
1710	mtpr	$0x18,$IPL		# lock out all so _whichqs==_qs
1711	bbcc	r0,_whichqs,sw1		# proc moved via interrupt
1712	movaq	_qs[r0],r1
1713	remque	*(r1),r2		# r2 = p = highest pri process
1714	bvs	badsw			# make sure something was there
1715	beql	sw2
1716	insv	$1,r0,$1,_whichqs	# still more procs in this queue
1717sw2:
1718	clrl	_noproc
1719	clrl	_runrun
1720#ifdef notdef
1721	tstl	P_WCHAN(r2)		## firewalls
1722	bneq	badsw			##
1723	cmpb	P_STAT(r2),$SRUN	##
1724	bneq	badsw			##
1725#endif
1726	clrl	P_RLINK(r2)		##
1727	movl	*P_ADDR(r2),r0
1728#ifdef notdef
1729	cmpl	r0,_masterpaddr		# resume of current proc is easy
1730	beql	res0
1731#endif
1732	movl	r0,_masterpaddr
1733	ashl	$PGSHIFT,r0,r0		# r0 = pcbb(p)
1734/* fall into... */
1735
1736/*
1737 * Resume(pf)
1738 */
1739JSBENTRY(Resume, R0)
1740	mtpr	$HIGH,$IPL			# no interrupts, please
1741	movl	_CMAP2,_u+PCB_CMAP2	# yech
1742	svpctx
1743	mtpr	r0,$PCBB
1744	ldpctx
1745	movl	_u+PCB_CMAP2,_CMAP2	# yech
1746	mtpr	$_CADDR2,$TBIS
1747res0:
1748	tstl	_u+PCB_SSWAP
1749	bneq	res1
1750	rei
1751res1:
1752	movl	_u+PCB_SSWAP,r0		# restore alternate saved context
1753	clrl	_u+PCB_SSWAP
1754	movq	(r0)+,r6			# restore r6, r7
1755	movq	(r0)+,r8			# restore r8, r9
1756	movq	(r0)+,r10			# restore r10, r11
1757	movq	(r0)+,r12			# restore ap, fp
1758	movl	(r0)+,r1			# saved sp
1759	cmpl	r1,sp				# must be a pop
1760	bgequ	1f
1761	pushab	2f
1762	calls	$1,_panic
1763	/* NOTREACHED */
17641:
1765	movl	r1,sp				# restore sp
1766	pushl	$PSL_PRVMOD			# return psl
1767	pushl	(r0)				# address to return to
1768	rei
1769
17702:	.asciz	"ldctx"
1771
1772/*
1773 * {fu,su},{byte,word}, all massaged by asm.sed to jsb's
1774 */
1775	.align	1
1776JSBENTRY(Fuword, R0)
1777	prober	$3,$4,(r0)
1778	beql	fserr
1779	movl	(r0),r0
1780	rsb
1781fserr:
1782	mnegl	$1,r0
1783	rsb
1784
1785	.align	1
1786JSBENTRY(Fubyte, R0)
1787	prober	$3,$1,(r0)
1788	beql	fserr
1789	movzbl	(r0),r0
1790	rsb
1791
1792	.align	1
1793JSBENTRY(Suword, R0|R1)
1794	probew	$3,$4,(r0)
1795	beql	fserr
1796	movl	r1,(r0)
1797	clrl	r0
1798	rsb
1799
1800	.align	1
1801JSBENTRY(Subyte, R0|R1)
1802	probew	$3,$1,(r0)
1803	beql	fserr
1804	movb	r1,(r0)
1805	clrl	r0
1806	rsb
1807
1808/*
1809 * Copy 1 relocation unit (NBPG bytes)
1810 * from user virtual address to physical address
1811 */
1812ENTRY(copyseg, 0)
1813	bisl3	$PG_V|PG_KW,8(ap),_CMAP2
1814	mtpr	$_CADDR2,$TBIS	# invalidate entry for copy
1815	movc3	$NBPG,*4(ap),_CADDR2
1816	ret
1817
1818/*
1819 * zero out physical memory
1820 * specified in relocation units (NBPG bytes)
1821 */
1822ENTRY(clearseg, 0)
1823	bisl3	$PG_V|PG_KW,4(ap),_CMAP1
1824	mtpr	$_CADDR1,$TBIS
1825	movc5	$0,(sp),$0,$NBPG,_CADDR1
1826	ret
1827
1828/*
1829 * Check address.
1830 * Given virtual address, byte count, and rw flag
1831 * returns 0 on no access.
1832 */
1833ENTRY(useracc, 0)
1834	movl	4(ap),r0		# get va
1835	movl	8(ap),r1		# count
1836	tstl	12(ap)			# test for read access ?
1837	bneq	userar			# yes
1838	cmpl	$NBPG,r1			# can we do it in one probe ?
1839	bgeq	uaw2			# yes
1840uaw1:
1841	probew	$3,$NBPG,(r0)
1842	beql	uaerr			# no access
1843	addl2	$NBPG,r0
1844	acbl	$NBPG+1,$-NBPG,r1,uaw1
1845uaw2:
1846	probew	$3,r1,(r0)
1847	beql	uaerr
1848	movl	$1,r0
1849	ret
1850
1851userar:
1852	cmpl	$NBPG,r1
1853	bgeq	uar2
1854uar1:
1855	prober	$3,$NBPG,(r0)
1856	beql	uaerr
1857	addl2	$NBPG,r0
1858	acbl	$NBPG+1,$-NBPG,r1,uar1
1859uar2:
1860	prober	$3,r1,(r0)
1861	beql	uaerr
1862	movl	$1,r0
1863	ret
1864uaerr:
1865	clrl	r0
1866	ret
1867
1868/*
1869 * kernacc - check for kernel access privileges
1870 *
1871 * We can't use the probe instruction directly because
1872 * it ors together current and previous mode.
1873 */
1874 ENTRY(kernacc, 0)
1875	movl	4(ap),r0	# virtual address
1876	bbcc	$31,r0,kacc1
1877	bbs	$30,r0,kacerr
1878	mfpr	$SBR,r2		# address and length of page table (system)
1879	bbss	$31,r2,0f; 0:
1880	mfpr	$SLR,r3
1881	brb	kacc2
1882kacc1:
1883	bbsc	$30,r0,kacc3
1884	mfpr	$P0BR,r2	# user P0
1885	mfpr	$P0LR,r3
1886	brb	kacc2
1887kacc3:
1888	mfpr	$P1BR,r2	# user P1 (stack)
1889	mfpr	$P1LR,r3
1890kacc2:
1891	addl3	8(ap),r0,r1	# ending virtual address
1892	addl2	$NBPG-1,r1
1893	ashl	$-PGSHIFT,r0,r0
1894	ashl	$-PGSHIFT,r1,r1
1895	bbs	$31,4(ap),kacc6
1896	bbc	$30,4(ap),kacc6
1897	cmpl	r0,r3		# user stack
1898	blss	kacerr		# address too low
1899	brb	kacc4
1900kacc6:
1901	cmpl	r1,r3		# compare last page to P0LR or SLR
1902	bgtr	kacerr		# address too high
1903kacc4:
1904	movl	(r2)[r0],r3
1905	bbc	$31,4(ap),kacc4a
1906	bbc	$31,r3,kacerr	# valid bit is off
1907kacc4a:
1908	cmpzv	$27,$4,r3,$1	# check protection code
1909	bleq	kacerr		# no access allowed
1910	tstb	12(ap)
1911	bneq	kacc5		# only check read access
1912	cmpzv	$27,$2,r3,$3	# check low 2 bits of prot code
1913	beql	kacerr		# no write access
1914kacc5:
1915	aoblss	r1,r0,kacc4	# next page
1916	movl	$1,r0		# no errors
1917	ret
1918kacerr:
1919	clrl	r0		# error
1920	ret
1921/*
1922 * Extracted and unrolled most common case of pagein (hopefully):
1923 *	resident and not on free list (reclaim of page is purely
1924 *	for the purpose of simulating a reference bit)
1925 *
1926 * Built in constants:
1927 *	CLSIZE of 2, any bit fields in pte's
1928 */
1929	.text
1930	.globl	Fastreclaim
1931Fastreclaim:
1932	PUSHR
1933#ifdef GPROF
1934	movl	fp,-(sp)
1935	movab	12(sp),fp
1936	jsb	mcount
1937	movl	(sp)+,fp
1938#endif GPROF
1939	extzv	$9,$23,28(sp),r3	# virtual address
1940	bicl2	$1,r3			# v = clbase(btop(virtaddr));
1941	movl	_u+U_PROCP,r5		# p = u.u_procp
1942					# from vtopte(p, v) ...
1943	movl	$1,r2			# type = CTEXT;
1944	cmpl	r3,P_TSIZE(r5)
1945	jlssu	1f			# if (isatsv(p, v)) {
1946	addl3	P_TSIZE(r5),P_DSIZE(r5),r0
1947	cmpl	r3,r0
1948	jgequ	2f
1949	clrl	r2			#	type = !CTEXT;
19501:
1951	ashl	$2,r3,r4
1952	addl2	P_P0BR(r5),r4		#	tptopte(p, vtotp(p, v));
1953	jbr	3f
19542:
1955	cvtwl	P_SZPT(r5),r4		# } else (isassv(p, v)) {
1956	ashl	$7,r4,r4
1957	subl2	$0x400000,r4
1958	addl2	r3,r4
1959	ashl	$2,r4,r4
1960	addl2	P_P0BR(r5),r4		#	sptopte(p, vtosp(p, v));
1961	clrl	r2			# 	type = !CTEXT;
19623:					# }
1963	bitb	$0x82,3(r4)
1964	beql	2f			# if (pte->pg_v || pte->pg_fod)
1965	POPR; rsb			#	let pagein handle it
19662:
1967	bicl3	$0xffe00000,(r4),r0
1968	jneq	2f			# if (pte->pg_pfnum == 0)
1969	POPR; rsb			# 	let pagein handle it
19702:
1971	subl2	_firstfree,r0
1972	ashl	$-1,r0,r0
1973	incl	r0			# pgtocm(pte->pg_pfnum)
1974	mull2	$SZ_CMAP,r0
1975	addl2	_cmap,r0		# &cmap[pgtocm(pte->pg_pfnum)]
1976	tstl	r2
1977	jeql	2f			# if (type == CTEXT &&
1978	jbc	$C_INTRANS,(r0),2f	#     c_intrans)
1979	POPR; rsb			# 	let pagein handle it
19802:
1981	jbc	$C_FREE,(r0),2f		# if (c_free)
1982	POPR; rsb			# 	let pagein handle it
19832:
1984	bisb2	$0x80,3(r4)		# pte->pg_v = 1;
1985	jbc	$26,4(r4),2f		# if (anycl(pte, pg_m)
1986	bisb2	$0x04,3(r4)		#	pte->pg_m = 1;
19872:
1988	bicw3	$0x7f,2(r4),r0
1989	bicw3	$0xff80,6(r4),r1
1990	bisw3	r0,r1,6(r4)		# distcl(pte);
1991	ashl	$PGSHIFT,r3,r0
1992	mtpr	r0,$TBIS
1993	addl2	$NBPG,r0
1994	mtpr	r0,$TBIS		# tbiscl(v);
1995	tstl	r2
1996	jeql	2f			# if (type == CTEXT)
1997	movl	P_TEXTP(r5),r0
1998	movl	X_CADDR(r0),r5		# for (p = p->p_textp->x_caddr; p; ) {
1999	jeql	2f
2000	ashl	$2,r3,r3
20013:
2002	addl3	P_P0BR(r5),r3,r0	#	tpte = tptopte(p, tp);
2003	bisb2	$1,P_FLAG+3(r5)		#	p->p_flag |= SPTECHG;
2004	movl	(r4),(r0)+		#	for (i = 0; i < CLSIZE; i++)
2005	movl	4(r4),(r0)		#		tpte[i] = pte[i];
2006	movl	P_XLINK(r5),r5		#	p = p->p_xlink;
2007	jneq	3b			# }
20082:					# collect a few statistics...
2009	incl	_u+U_RU+RU_MINFLT	# u.u_ru.ru_minflt++;
2010	moval	_cnt,r0
2011	incl	V_FAULTS(r0)		# cnt.v_faults++;
2012	incl	V_PGREC(r0)		# cnt.v_pgrec++;
2013	incl	V_FASTPGREC(r0)		# cnt.v_fastpgrec++;
2014	incl	V_TRAP(r0)		# cnt.v_trap++;
2015	POPR
2016	addl2	$8,sp			# pop pc, code
2017	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
2018	rei
2019