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