xref: /original-bsd/sys/tahoe/tahoe/locore.s (revision dc4562f1)
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.19 (Berkeley) 07/12/91
7 */
8
9#include "tahoe/include/mtpr.h"
10#include "tahoe/include/trap.h"
11#include "tahoe/include/psl.h"
12#include "tahoe/include/pte.h"
13#include "tahoe/tahoe/cp.h"
14#include "tahoe/tahoe/mem.h"
15#include "tahoe/tahoe/SYS.h"
16
17#include "tahoe/math/fp.h"
18
19#include "sys/errno.h"
20#include "sys/syscall.h"
21#include "sys/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_ARP,_netisr,1f
333	andl2	$~(1<<NETISR_ARP),_netisr
334	callf	$4,_arpintr
3351:
336	bbc	$NETISR_IP,_netisr,1f
337	andl2	$~(1<<NETISR_IP),_netisr
338	callf	$4,_ipintr
3391:
340#endif
341#ifdef NS
342	bbc	$NETISR_NS,_netisr,1f
343	andl2	$~(1<<NETISR_NS),_netisr
344	callf	$4,_nsintr
3451:
346#endif
347#ifdef ISO
348	bbc	$NETISR_ISO,_netisr,1f
349	andl2	$~(1<<NETISR_ISO),_netisr
350	callf	$4,_clnlintr
3511:
352#endif
353	incl	_cnt+V_SOFT
354	POPR; REST_FPSTAT
355	rei
356
357SCBVEC(cnrint):
358	CHECK_SFE(4)
359	SAVE_FPSTAT(4); PUSHR;
360	pushl $CPCONS; callf $8,_cnrint;
361	incl	_intrcnt+I_CNR
362	incl	_cnt+V_INTR
363	POPR; REST_FPSTAT;
364	rei
365SCBVEC(cnxint):
366	CHECK_SFE(4)
367	SAVE_FPSTAT(4); PUSHR;
368	pushl $CPCONS; callf $8,_cnxint;
369	incl	_intrcnt+I_CNX
370	incl	_cnt+V_INTR
371	POPR; REST_FPSTAT;
372	rei
373SCBVEC(rmtrint):
374	CHECK_SFE(4)
375	SAVE_FPSTAT(4); PUSHR;
376	pushl $CPREMOT; callf $8,_cnrint;
377	incl	_intrcnt+I_RMTR
378	incl	_cnt+V_INTR
379	POPR; REST_FPSTAT;
380	rei
381SCBVEC(rmtxint):
382	CHECK_SFE(4)
383	SAVE_FPSTAT(4); PUSHR;
384	pushl $CPREMOT; callf $8,_cnxint;
385	incl	_intrcnt+I_RMTX
386	incl	_cnt+V_INTR
387	POPR; REST_FPSTAT;
388	rei
389
390#define PUSHPCPSL	pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp);
391
392SCBVEC(hardclock):
393	tstl	_clk_enable
394	bneq	1f
395	rei
3961:
397	CHECK_SFE(4)
398	SAVE_FPSTAT(4); PUSHR
399	PUSHPCPSL			# push pc and psl
400	callf	$12,_hardclock		# hardclock(pc,psl)
401	incl	_intrcnt+I_CLOCK
402	incl	_cnt+V_INTR		## temp so not to break vmstat -= HZ
403	POPR; REST_FPSTAT
404	rei
405SCBVEC(softclock):
406	CHECK_SFE(4)
407	SAVE_FPSTAT(4); PUSHR;
408	PUSHPCPSL				# push pc and psl
409	callf	$12,_softclock			# softclock(pc,psl)
410	incl	_cnt+V_SOFT
411	POPR; REST_FPSTAT
412	rei
413
414/*
415 * Stray VERSAbus interrupt catch routines
416 */
417	.data
418#define	PJ	.align 2; callf $4,_Xvstray
419	.globl	_catcher
420_catcher:
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	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
428	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
429	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
430	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
431	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
432	PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
433
434	.align	2
435	.globl	_cold
436_cold:	.long	0x3
437
438	.text
439SCBVEC(vstray):
440	.word	0
441	bbc	$0,_cold,2f		# system running?
442	bbc	$1,_cold,1f		# doing autoconfig?
443	jbr	3f			# random interrupt, ignore
4441:
445	mfpr	$IPL,r12		# ...setup br and cvec
446	subl3	$_catcher+7,-8(fp),r11; shar $3,r11,r11
447	addl2	$SCB_DEVBASE,r11
448	jbr	3f
4492:
450	PUSHR
451	subl3	$_catcher+7,-8(fp),r0; shar $3,r0,r0
452	addl3	$SCB_DEVBASE,r0,-(sp);
453	mfpr	$IPL,-(sp)
454	PRINTF(2, "stray intr ipl %x vec %x\n")
455	POPR
4563:	moval	0f,-8(fp); ret		# pop callf frame...
4570:	rei				# ...and return
458
459/*
460 * Trap and fault vector routines
461 */
462#define	TRAP(a)	pushl $T_/**/a; jbr alltraps
463
464/*
465 * Ast delivery (profiling and/or reschedule)
466 */
467
468SCBVEC(kspnotval):
469	CHECK_SFE(4)
470	pushl $0;
471	SAVE_FPSTAT(8)
472	TRAP(KSPNOTVAL)
473SCBVEC(privinflt):
474	CHECK_SFE(4)
475	pushl $0;
476	SAVE_FPSTAT(8)
477	TRAP(PRIVINFLT)
478SCBVEC(resopflt):
479	CHECK_SFE(4)
480	pushl $0;
481	SAVE_FPSTAT(8)
482	TRAP(RESOPFLT)
483SCBVEC(resadflt):
484	CHECK_SFE(4)
485	pushl $0;
486	SAVE_FPSTAT(8)
487	TRAP(RESADFLT)
488SCBVEC(bptflt):
489	CHECK_SFE(4)
490	pushl $0;
491	SAVE_FPSTAT(8)
492	TRAP(BPTFLT)
493SCBVEC(kdbintr):
494	CHECK_SFE(4);
495	pushl $0;
496	SAVE_FPSTAT(8);
497	TRAP(KDBTRAP);
498SCBVEC(tracep):
499	CHECK_SFE(4)
500	pushl $0;
501	SAVE_FPSTAT(8)
502	TRAP(TRCTRAP)
503SCBVEC(alignflt):
504#ifdef ALIGN
505	bitl	$PSL_CURMOD,4(sp)
506	jeql	align_excp		# Can't emulate for kernel mode !
507	jbr	non_aligned		# Only emulated for user mode.
508align_excp:
509#else
510	CHECK_SFE(4)
511#endif
512	pushl $0;
513	SAVE_FPSTAT(8)
514	TRAP(ALIGNFLT)
515SCBVEC(arithtrap):
516	CHECK_SFE(8)
517	SAVE_FPSTAT(8)
518	TRAP(ARITHTRAP)
519
520SCBVEC(protflt):
521	CHECK_SFE(12)
522	bitl	$1,(sp)+
523	jneq	segflt
524	SAVE_FPSTAT(8)
525	TRAP(PROTFLT)
526segflt:
527	SAVE_FPSTAT(8)
528	TRAP(SEGFLT)
529
530SCBVEC(fpm):			# Floating Point Emulation
531#ifdef FPE
532	CHECK_SFE(16)
533	SAVE_FPSTAT(16)
534	incl	_cnt+V_FPE	# count emulation traps
535	callf	$4,_fpemulate
536	REST_FPSTAT
537#endif
538	moval	8(sp),sp	# Pop operand
539	tstl	(sp)		# Stack= PSL, PC, return_code
540	jneq	_Xarithtrap	# If not OK, emulate F.P. exception
541	movab	4(sp),sp	# Else remove return_code and
542	rei
543
544SCBVEC(sfexcep):
545	CHECK_SFE(4)
546	pushl $0
547	SAVE_FPSTAT(8)
548	TRAP(ASTFLT)
549
550SCBVEC(transflt):
551	CHECK_SFE(12)
552	bitl	$2,(sp)+
553	bneq	tableflt
554pageflt:
555	SAVE_FPSTAT(8)
556	TRAP(PAGEFLT)
557tableflt:
558	SAVE_FPSTAT(8)
559	TRAP(TABLEFLT)
560
561#define REST_STACK	movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
562
563alltraps:
564	mfpr	$USP,-(sp);
565	callf	$4,_trap;
566	mtpr	(sp)+,$USP
567	incl	_cnt+V_TRAP
568	REST_STACK			# pop type, code, and fp stuff
569	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
570	rei
571
572SCBVEC(syscall):
573	CHECK_SFE(8)
574	SAVE_FPSTAT(8)
575	pushl	$T_SYSCALL
576	mfpr	$USP,-(sp);
577	callf	$4,_syscall;
578	mtpr	(sp)+,$USP
579	incl	_cnt+V_SYSCALL
580	REST_STACK			# pop type, code, and fp stuff
581	mtpr	$HIGH,$IPL		## dont go to a higher IPL (GROT)
582	rei
583
584/*
585 * System page table.
586 *
587 * Mbmap and Usrptmap are enlarged by CLSIZE entries
588 * as they are managed by resource maps starting with index 1 or CLSIZE.
589 */
590#define	vaddr(x)	((((x)-_Sysmap)/4)*NBPG+SYSTEM)
591#define	SYSMAP(mname, vname, npte)			\
592_/**/mname:	.globl	_/**/mname;		\
593	.space	(npte)*4;			\
594	.globl	_/**/vname;			\
595	.set	_/**/vname,vaddr(_/**/mname)
596#define	ADDMAP(npte)	.space	(npte)*4
597
598	.data
599	.align	2
600	SYSMAP(Sysmap	,Sysbase	,SYSPTSIZE	)
601	SYSMAP(Forkmap	,forkutl	,UPAGES		)
602	SYSMAP(Xswapmap	,xswaputl	,UPAGES		)
603	SYSMAP(Xswap2map,xswap2utl	,UPAGES		)
604	SYSMAP(Swapmap	,swaputl	,UPAGES		)
605	SYSMAP(Pushmap	,pushutl	,UPAGES		)
606	SYSMAP(Vfmap	,vfutl		,UPAGES		)
607	SYSMAP(CMAP1	,CADDR1		,1		)
608	SYSMAP(CMAP2	,CADDR2		,1		)
609	SYSMAP(mmap	,vmmap		,1		)
610	SYSMAP(alignmap	,alignutl	,1		)	/* XXX */
611	SYSMAP(msgbufmap,msgbuf		,MSGBUFPTECNT	)
612	SYSMAP(Mbmap	,mbutl		,NMBCLUSTERS*MCLBYTES/NBPG+CLSIZE )
613#ifdef MFS
614#include "ufs/mfsiom.h"
615	/*
616	 * Used by the mfs_doio() routine for physical I/O
617	 */
618	SYSMAP(Mfsiomap	,mfsiobuf	,MFS_MAPREG )
619#endif /* MFS */
620#ifdef NFS
621#include "nfs/nfsiom.h"
622	/*
623	 * Used by the nfs_doio() routine for physical I/O
624	 */
625	SYSMAP(Nfsiomap	,nfsiobuf	,NFS_MAPREG )
626#endif /* NFS */
627	/*
628	 * This is the map used by the kernel memory allocator.
629	 * It is expanded as necessary by the special features
630	 * that use it.
631	 */
632	SYSMAP(kmempt	,kmembase	,NKMEMCLUSTERS*CLSIZE	)
633#ifdef	SYSVSHM
634				ADDMAP(	SHMMAXPGS	)
635#endif
636#ifdef	GPROF
637				ADDMAP( 600*CLSIZE	)
638#endif
639	/*
640	 * Enlarge kmempt as needed for bounce buffers allocated
641	 * by tahoe controllers.
642	 */
643#include "hd.h"
644#if NHD > 0
645				ADDMAP(	NHDC*(MAXPHYS/NBPG+CLSIZE) )
646#endif
647#include "dk.h"
648#if NDK > 0
649				ADDMAP(	NVD*(MAXPHYS/NBPG+CLSIZE) )
650#endif
651#include "yc.h"
652#if NYC > 0
653				ADDMAP(	NCY*(MAXPHYS/NBPG+CLSIZE) )
654#endif
655#include "mp.h"
656				ADDMAP(	NMP*14		)
657	SYSMAP(ekmempt	,kmemlimit	,0		)
658
659	SYSMAP(VMEMbeg	,vmembeg	,0		)
660	SYSMAP(VMEMmap	,vmem		,VBIOSIZE 	)
661	SYSMAP(VMEMmap1	,vmem1		,0		)
662#include "ace.h"
663#if NACE > 0
664				ADDMAP(	NACE*32	)
665#endif
666#if NHD > 0
667				ADDMAP( NHDC )
668#endif
669#include "vx.h"
670#if NVX > 0
671				ADDMAP( NVX * 16384/NBPG )
672#endif
673	SYSMAP(VMEMend	,vmemend	,0		)
674
675	SYSMAP(VBmap	,vbbase		,CLSIZE		)
676#if NHD > 0
677				ADDMAP(	NHDC*(MAXPHYS/NBPG+CLSIZE) )
678#endif
679#if NDK > 0
680				ADDMAP(	NVD*(MAXPHYS/NBPG+CLSIZE) )
681#endif
682#if NYC > 0
683				ADDMAP(	NCY*(MAXPHYS/NBPG+CLSIZE) )
684#endif
685				ADDMAP(	NMP*14		)
686	SYSMAP(eVBmap	,vbend		,0		)
687
688	SYSMAP(Usrptmap	,usrpt		,USRPTSIZE+CLSIZE )
689eSysmap:
690	.globl	_Syssize
691	.set	_Syssize,(eSysmap-_Sysmap)/4
692
693	.text
694/*
695 * Initialization
696 *
697 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
698 */
699	.align	2
700	.globl	start
701start:
702	.word	0
703/* set system control block base and system page table params */
704	mtpr	$_scb-SYSTEM,$SCBB
705	mtpr	$_Sysmap-SYSTEM,$SBR
706	mtpr	$_Syssize,$SLR
707/* double map the kernel into the virtual user addresses of phys mem */
708	mtpr	$_Sysmap,$P0BR
709	mtpr	$_Syssize,$P0LR
710	mtpr	$_Sysmap,$P1BR			# against Murphy
711	mtpr	$_Syssize,$P1LR
712/* set ISP */
713	movl	$_intstack-SYSTEM+NISP*NBPG,sp	# still physical
714	mtpr	$_intstack+NISP*NBPG,$ISP
715/* count up memory; _physmem contains limit */
716	clrl	r7
717	shll	$PGSHIFT,_physmem,r8
718	decl	r8
7191:	pushl	$1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
720	ACBL(r8,$64*1024,r7,1b)
7219:
722/* clear memory from kernel bss and pages for proc 0 u. and page table */
723	movab	_edata,r6; andl2 $~SYSTEM,r6
724	movab	_end,r5; andl2 $~SYSTEM,r5
725#ifdef KADB
726	subl2	$4,r5
7271:	clrl	(r6); ACBL(r5,$4,r6,1b)		# clear just bss
728	addl2	$4,r5
729	bbc	$6,r11,0f			# check RB_KDB
730	andl3	$~SYSTEM,r9,r5			# skip symbol & string tables
731	andl3	$~SYSTEM,r9,r6
732#endif
7330:	orl3	$SYSTEM,r5,r9			# convert to virtual address
734	addl2	$NBPG-1,r9			# roundup to next page
735	addl2	$(UPAGES*NBPG)+NBPG+NBPG,r5
7361:	clrl	(r6); ACBL(r5,$4,r6,1b)
737/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */
738	orw2	$0x01fff,_trap
739	orw2	$0x01fff,_syscall
740#ifdef FPE
741	orw2	$0x01fff,_fpemulate
742#endif
743	orw2	$0x01ffc,_panic			# for debugging (no r0|r1)
744	callf	$4,_fixctlrmask			# setup for autoconfig
745/* initialize system page table: scb and int stack writeable */
746	clrl	r2
747	movab	eintstack,r1
748	andl2	$~SYSTEM,r1
749	shrl 	$PGSHIFT,r1,r1			# r1-page number of eintstack
750/* make 1st page processor storage read/only, 2nd read/write */
751	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
752	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]; incl r2;
753/* other parts of the system are read/write for kernel */
7541:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2];	# data:kernel write+phys=virtual
755	aoblss r1,r2,1b
756/* make rsstk read-only as red zone for interrupt stack */
757	andl2	$~PG_PROT,_rsstkmap
758	orl2	$PG_V|PG_KR,_rsstkmap
759/* make kernel text space read-only */
760	movab	_etext+NBPG-1,r1
761	andl2	$~SYSTEM,r1
762	shrl 	$PGSHIFT,r1,r1
7631:	orl3	$PG_V|PG_KR,r2,_Sysmap[r2]
764	aoblss r1,r2,1b
765/* make kernel data, bss, read-write */
766	andl3	$~SYSTEM,r9,r1
767	shrl 	$PGSHIFT,r1,r1
7681:	orl3	$PG_V|PG_KW,r2,_Sysmap[r2]
769	aoblss r1,r2,1b
770/* go to mapped mode, have to change both pc and sp to system addresses */
771	mtpr	$1,$TBIA
772	mtpr	$1,$PADC			# needed by HW parity&ECC logic
773	mtpr	$1,$PACC			# just in case
774	mtpr 	$1,$MME
775	movab	SYSTEM(sp),sp
776	jmp 	*$0f
7770:
778/* disable any interrupts */
779	movl	$0,_intenable
780/* init mem sizes */
781	shrl	$PGSHIFT,r7,_physmem
782/* setup context for proc[0] == scheduler */
783	andl3	$~SYSTEM,r9,r6			# convert to physical
784	andl2	$~(NBPG-1),r6			# make page boundary
785/* setup page table for proc[0] */
786	shrl	$PGSHIFT,r6,r3			# r3 = btoc(r6)
787	orl3	$PG_V|PG_KW,r3,_Usrptmap	# init first upt entry
788	incl	r3				# r3 - next page
789	movab	_usrpt,r0			# r0 - first user page
790	mtpr	r0,$TBIS
791/* init p0br, p0lr */
792	mtpr	r0,$P0BR			# no p0 for proc[0]
793	mtpr	$0,$P0LR
794	mtpr	r0,$P1BR			# no p1 either
795	mtpr	$0,$P1LR
796/* init p2br, p2lr */
797	movab	NBPG(r0),r0
798	movl	$PPAGES-UPAGES,r1
799	mtpr	r1,$P2LR
800	moval	-4*PPAGES(r0),r2
801	mtpr	r2,$P2BR
802/* setup mapping for UPAGES of _u */
803	clrl	r2
804	movl 	$SYSTEM,r1
805	addl2 	$UPAGES,r3
806	jbr 2f
8071:	decl	r3
808	moval	-NBPG(r1),r1	# r1 = virtual add of next (downward) _u page
809	subl2	$4,r0		# r0 = pte address
810	orl3	$PG_V|PG_URKW,r3,(r0)
811	mtpr	r1,$TBIS
8122:	aobleq	$UPAGES,r2,1b
813/* initialize (slightly) the pcb */
814	movab	UPAGES*NBPG(r1),PCB_KSP(r1)	# KSP starts at end of _u
815	movl	r1,PCB_USP(r1)			# USP starts just below _u
816	mfpr	$P0BR,PCB_P0BR(r1)
817	mfpr	$P0LR,PCB_P0LR(r1)
818	mfpr	$P1BR,PCB_P1BR(r1)
819	mfpr	$P1LR,PCB_P1LR(r1)
820	mfpr	$P2BR,PCB_P2BR(r1)
821	mfpr	$P2LR,PCB_P2LR(r1)
822	movl	$CLSIZE,PCB_SZPT(r1)		# init u.u_pcb.pcb_szpt
823	movl	r9,PCB_R9(r1)			# r9 obtained from boot
824	movl	r10,PCB_R10(r1)			# r10 obtained from boot
825	movl	r11,PCB_R11(r1)			# r11 obtained from CP on boot
826	movab	1f,PCB_PC(r1)			# initial pc
827	clrl	PCB_PSL(r1)			# kernel mode, ipl=0
828	shll	$PGSHIFT,r3,r3
829	mtpr	r3,$PCBB			# first pcbb (physical)
830/* go to kernel mode */
831	ldpctx
832	rei					# Actually next instruction:
833/* put signal trampoline code in u. area */
8341:	movab	sigcode,r0
835	movab	_u+PCB_SIGC,r1
836	movl	$19,r2
837	movblk
838/* save boot device in global _bootdev */
839	movl	r10,_bootdev
840/* save reboot flags in global _boothowto */
841	movl	r11,_boothowto
842#ifdef KADB
843/* save end of symbol & string table in global _bootesym */
844	subl3	$NBPG-1,r9,_bootesym
845#endif
846/* calculate firstaddr, and call main() */
847	andl3	$~SYSTEM,r9,r0
848	shrl	$PGSHIFT,r0,-(sp)
849	addl2	$UPAGES+1,(sp)			# first physical unused page
850	callf 	$8,_main
851/* proc[1] == /etc/init now running here in kernel mode; run icode */
852	pushl	$PSL_CURMOD			# User mode PSL
853	pushl $0				# PC = 0 (virtual now)
854	rei
855
856/*
857 * Mask for saving/restoring registers on entry to
858 * a user signal handler.  Space for the registers
859 * is reserved in sendsig, so beware if you want
860 * to change the mask.
861 */
862#define	SIGREGS	(R0|R1|R2|R3|R4|R5)
863	.align	2
864	.globl	sigcode
865sigcode:
866	storer	$SIGREGS,16(sp)	# save volatile registers
867	calls	$4*3+4,*12(sp)	# params pushed by sendsig for handler
868	loadr	$SIGREGS,4(sp)	# restore volatile registers
869	movab	24(sp),fp	# use parameter list set up in sendsig
870	kcall	$SYS_sigreturn	# cleanup mask and onsigstack
871	halt			# sigreturn does not return!
872
873	.globl	_icode
874	.globl	_initflags
875	.globl	_szicode
876	.data
877/*
878 * Icode is copied out to process 1 to exec /etc/init.
879 * If the exec fails, process 1 exits.
880 */
881	.align	2
882_icode:
883	/* try /sbin/init */
884	pushl	$0
885	pushab	b`argv1-l0(pc)
886l0:	pushab	b`init1-l1(pc)
887l1:	pushl	$2
888	movab	(sp),fp
889	kcall	$SYS_execve
890	/* try /etc/init */
891	pushl	$0
892	pushab	b`argv2-l2(pc)
893l2:	pushab	b`init2-l3(pc)
894l3:	pushl	$2
895	movab	(sp),fp
896	kcall	$SYS_execve
897	/* give up */
898	pushl	r0
899	pushl	$1
900	movab	(sp),fp
901	kcall	$SYS_exit
902
903init1:	.asciz	"/sbin/init"
904init2:	.asciz	"/etc/init"
905	.align	2
906_initflags:
907	.long	0
908argv1:	.long	init1+6-_icode
909	.long	_initflags-_icode
910	.long	0
911argv2:	.long	init2+5-_icode
912	.long	_initflags-_icode
913	.long	0
914_szicode:
915	.long	_szicode-_icode
916	.text
917
918/*
919 * Primitives
920 */
921
922/*
923 * badaddr(addr, len)
924 *	see if access addr with a len type instruction causes a machine check
925 *	len is length of access (1=byte, 2=short, 4=long)
926 *	r0 = 0 means good(exists); r0 =1 means does not exist.
927 */
928ENTRY(badaddr, R3|R4)
929	mfpr	$IPL,r1
930	mtpr	$HIGH,$IPL
931	movl	_scb+SCB_BUSERR,r2
932	movl	4(fp),r3
933	movl	8(fp),r4
934	movab	9f,_scb+SCB_BUSERR
935	bbc	$0,r4,1f; tstb	(r3)
9361:	bbc	$1,r4,1f; tstw	(r3)
9371:	bbc	$2,r4,1f; tstl	(r3)
9381:	clrl	r0
9392:	movl	r2,_scb+SCB_BUSERR
940	mtpr	r1,$IPL
941	ret
942
943/*
944 * wbadaddr(addr, len, value)
945 *	see if write of value to addr with a len type instruction causes
946 *	a machine check
947 *	len is length of access (1=byte, 2=short, 4=long)
948 *	r0 = 0 means good(exists); r0 =1 means does not exist.
949 */
950ENTRY(wbadaddr, R3|R4)
951	mfpr	$IPL,r1
952	mtpr	$HIGH,$IPL
953	movl	_scb+SCB_BUSERR,r2
954	movl	4(fp),r3
955	movl	8(fp),r4
956	movab	9f,_scb+SCB_BUSERR
957	bbc	$0,r4,1f; movb	15(fp), (r3)
9581:	bbc	$1,r4,1f; movw	14(fp), (r3)
9591:	bbc	$2,r4,1f; movl	12(fp), (r3)
9601:	movl	$30000,r0		# delay for error interrupt
9611:	decl	r0
962	jneq	1b
9632:	movl	r2,_scb+SCB_BUSERR	# made it w/o machine checks; r0 is 0
964	mtpr	r1,$IPL
965	ret
966
967	.align	2
9689:				# catch buss error (if it comes)
969	andl3	4(sp),$ERRCD,r0
970	cmpl	r0,$APE
971	jneq	1f
972	halt			# address parity error
9731:	cmpl	r0,$VBE
974	jneq	1f
975	halt			# Versabus error
9761:
977	movl	$1,r0		# Anything else = bad address
978	movab	8(sp),sp	# discard buss error trash
979	movab	2b,(sp)		# new program counter on stack.
980	rei
981
982/*
983 * badcyaddr(addr)
984 *	see if access tape master controller addr causes a bus error
985 *	r0 = 0: no error; r0 = 1: timeout error.
986 */
987ENTRY(badcyaddr, 0)
988	mfpr	$IPL,r1
989	mtpr	$HIGH,$IPL
990	clrl	r2
991	movab	2f,nofault
992	movob	$-1, *4(fp)
9931:	aobleq	$1000, r2, 1b
994	clrl	nofault			# made it w/o bus error
995	clrl	r0
996	jbr	3f
9972:	movl	$1,r0
9983:	mtpr	r1,$IPL
999	ret
1000
1001/*
1002 * peek(addr)
1003 *	fetch word and catch any bus error
1004 */
1005ENTRY(peek, 0)
1006	mfpr	$IPL,r1
1007	mtpr	$0x18,$IPL	# not reentrant
1008	movl	4(fp),r2
1009	movab	1f,nofault
1010	movw	(r2),r0
1011	clrl	nofault
1012	andl2	$0xffff,r0
1013	jbr	2f
10141:	movl	$-1,r0		# bus error
10152:	mtpr	r1,$IPL
1016	ret
1017
1018/*
1019 * poke(addr, val)
1020 *	write word and catch any bus error
1021 */
1022ENTRY(poke, R3)
1023	mfpr	$IPL,r1
1024	mtpr	$0x18,$IPL	# not reentrant
1025	movl	4(fp),r2
1026	movl	8(fp),r3
1027	clrl	r0
1028	movab	1f,nofault
1029	movw	r3,(r2)
1030	clrl	nofault
1031	jbr	2f
10321:	movl	$-1,r0		# bus error
10332:	mtpr	r1,$IPL
1034	ret
1035
1036/*
1037 * Copy a potentially overlapping block of memory.
1038 *
1039 * ovbcopy(src, dst, count)
1040 *	caddr_t src, dst; unsigned count;
1041 */
1042ENTRY(ovbcopy, R3|R4)
1043	movl	4(fp),r0
1044	movl	8(fp),r1
1045	movl	12(fp),r2
1046	cmpl	r0,r1
1047	bgtru	1f			# normal forward case
1048	beql	2f			# equal, nothing to do
1049	addl2	r2,r0			# may be overlapping
1050	cmpl	r0,r1
1051	bgtru	3f
1052	subl2	r2,r0			# normal forward case
10531:
1054	movblk
10552:
1056	ret
10573:
1058	addl2	r2,r1			# overlapping, must do backwards
1059	subl3	r0,r1,r3
1060	movl	r2,r4
1061	jbr	5f
10624:
1063	subl2	r3,r0
1064	subl2	r3,r1
1065	movl	r3,r2
1066	movblk
1067	subl2	r3,r0
1068	subl2	r3,r1
1069	subl2	r3,r4
10705:
1071	cmpl	r4,r3
1072	jgtr	4b
1073	movl	r4,r2
1074	subl2	r2,r0
1075	subl2	r2,r1
1076	movblk
1077	ret
1078
1079/*
1080 * Copy a null terminated string from the user address space into
1081 * the kernel address space.
1082 *
1083 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
1084 */
1085ENTRY(copyinstr, 0)
1086	movl	12(fp),r5		# r5 = max length
1087	jlss	5f
1088	movl	8(fp),r4		# r4 = kernel address
1089	movl	4(fp),r0		# r0 = user address
1090	andl3	$(NBPG*CLSIZE-1),r0,r2	# r2 = bytes on first page
1091	subl3	r2,$(NBPG*CLSIZE),r2
10921:
1093	cmpl	r5,r2			# r2 = min(bytes on page, length left);
1094	jgeq	2f
1095	movl	r5,r2
10962:
1097	prober	$1,(r0),r2		# bytes accessible?
1098	jeql	5f
1099	subl2	r2,r5			# update bytes left count
1100	movl	r2,r3			# r3 = saved count
1101	movl	r0,r1
1102	cmps3				# check for null
1103	tstl	r2
1104	jneq	3f
1105	subl2	r3,r0			# back up r0
1106	movl	r4,r1
1107	movl	r3,r2
1108	movblk				# copy in next piece
1109	movl	r1,r4
1110	movl	$(NBPG*CLSIZE),r2	# check next page
1111	tstl	r5			# run out of space?
1112	jneq	1b
1113	movl	$ENAMETOOLONG,r0	# set error code and return
1114	jbr	6f
11153:
1116	tstl	16(fp)			# return length?
1117	beql	4f
1118	subl3	r5,12(fp),r5		# actual len = maxlen - unused pages
1119	subl2	r2,r5			#	- unused on this page
1120	addl3	$1,r5,*16(fp)		#	+ the null byte
11214:
1122	movl	r4,r1
1123	subl3	r2,r3,r2		# calc char cnt
1124	subl2	r2,r0			# back up r0
1125	incl	r2			# add on null byte
1126	movblk				# copy last piece
1127	clrl	r0
1128	ret
11295:
1130	movl	$EFAULT,r0
11316:
1132	tstl	16(fp)
1133	beql	7f
1134	subl3	r5,12(fp),*16(fp)
11357:
1136	ret
1137
1138/*
1139 * Copy a null terminated string from the kernel
1140 * address space to the user address space.
1141 *
1142 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1143 */
1144ENTRY(copyoutstr, 0)
1145	movl	12(fp),r5		# r5 = max length
1146	jlss	5f
1147	movl	4(fp),r0		# r0 = kernel address
1148	movl	8(fp),r4		# r4 = user address
1149	andl3	$(NBPG*CLSIZE-1),r4,r2	# r2 = bytes on first page
1150	subl3	r2,$(NBPG*CLSIZE),r2
11511:
1152	cmpl	r5,r2			# r2 = min(bytes on page, length left);
1153	jgeq	2f
1154	movl	r5,r2
11552:
1156	probew	$1,(r4),r2		# bytes accessible?
1157	jeql	5f
1158	subl2	r2,r5			# update bytes left count
1159	movl	r2,r3			# r3 = saved count
1160	movl	r0,r1
1161/*
1162 * This is a workaround for a microcode bug that causes
1163 * a trap type 9 when cmps3/movs3 touches the last byte
1164 * on a valid page immediately followed by an invalid page.
1165 */
1166#ifdef good_cmps3
1167	cmps3				# check for null
1168	tstl	r2
1169	jneq	3b
1170#else
1171	decl	r2
1172	beql	9f			# cannot handle case of r2 == 0!
1173	cmps3				# check for null up to last byte
11749:
1175	incl	r2
1176	cmpl	$1,r2			# get to last byte on page?
1177	bneq	3b
1178	tstb	(r0)			# last byte on page null?
1179	beql	3b
1180	incl	r0			# not null, so bump pointer
1181#endif not good_cmps3
1182	subl2	r3,r0			# back up r0
1183	movl	r4,r1
1184	movl	r3,r2
1185	movblk				# copy out next piece
1186	movl	r1,r4
1187	movl	$(NBPG*CLSIZE),r2	# check next page
1188	tstl	r5			# run out of space?
1189	jneq	1b
1190	movl	$ENAMETOOLONG,r0	# set error code and return
1191	jbr	6b
11925:
1193	clrl	*$0		# this should never execute, if it does
1194	movl	$EFAULT,r0	#  save me a core dump (mkm - 9/87)
11956:
1196	tstl	16(fp)
1197	beql	7f
1198	subl3	r5,12(fp),*16(fp)
11997:
1200	ret
1201
1202
1203/*
1204 * Copy a null terminated string from one point to another in
1205 * the kernel address space.
1206 *
1207 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1208 */
1209ENTRY(copystr, 0)
1210	movl	12(fp),r3		# r3 = max length
1211	jlss	5b
1212	movl	4(fp),r0		# r0 = src address
1213	movl	8(fp),r4		# r4 = dest address
1214	clrl	r5			# r5 = bytes left
1215	movl	r3,r2			# r2 = max bytes to copy
1216	movl	r0,r1
1217	cmps3				# check for null
1218	tstl	r2
1219	jneq	3b
1220	subl2	r3,r0			# back up r0
1221	movl	r4,r1
1222	movl	r3,r2
1223	movblk				# copy next piece
1224	movl	$ENAMETOOLONG,r0	# set error code and return
1225	jbr	6b
1226
1227/*
1228 * Copy a block of data from the user address space into
1229 * the kernel address space.
1230 *
1231 * copyin(fromaddr, toaddr, count)
1232 */
1233ENTRY(copyin, 0)
1234	movl	12(fp),r0		# copy length
1235	blss	9f
1236	movl	4(fp),r1		# copy user address
1237	cmpl	$(CLSIZE*NBPG),r0	# probing one page or less ?
1238	bgeq	2f			# yes
12391:
1240	prober	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible ?
1241	beql	9f			# no
1242	addl2	$(CLSIZE*NBPG),r1	# incr user address ptr
1243	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
12442:
1245	prober	$1,(r1),r0		# bytes accessible ?
1246	bneq	7f			# yes
1247	tstl	r0			# copin 0 bytes ?
1248	bneq	9f			# no, can't copyin
1249	ret				# lie!
12507:
1251	MOVC3(4(fp),8(fp),12(fp))
1252	clrl	r0
1253	ret
12549:
1255	movl	$EFAULT,r0
1256	ret
1257
1258/*
1259 * Copy a block of data from the kernel
1260 * address space to the user address space.
1261 *
1262 * copyout(fromaddr, toaddr, count)
1263 */
1264ENTRY(copyout, 0)
1265	movl	12(fp),r0		# get count
1266	blss	9b
1267	movl	8(fp),r1		# get user address
1268	cmpl	$(CLSIZE*NBPG),r0	# can do in one probew?
1269	bgeq	2f			# yes
12701:
1271	probew	$1,(r1),$(CLSIZE*NBPG)	# bytes accessible?
1272	beql	9b			# no
1273	addl2	$(CLSIZE*NBPG),r1	# increment user address
1274	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b)	# reduce count and loop
12752:
1276	probew	$1,(r1),r0		# bytes accessible?
1277	bneq	7f			# yes
1278	tstl	r0			# copin 0 bytes ?
1279	bneq	9b			# no, can't copyin
1280	ret				# lie!
12817:
1282	MOVC3(4(fp),8(fp),12(fp))
1283	clrl	r0
1284	ret
1285
1286/*
1287 * savectx is like setjmp but saves all registers.
1288 * Called before swapping out the u. area, restored by resume()
1289 * below.
1290 */
1291ENTRY(savectx, 0)
1292	movl	4(fp),r2
1293	storer	$0x1ff8,(r2); addl2 $40,r2	# r3-r12
1294	movl	(fp),(r2); addl2 $4,r2		# fp
1295	movab	8(fp),(r2); addl2 $4,r2		# sp
1296	movl	-8(fp),(r2)			# pc
1297	clrl	r0
1298	ret
1299
1300#ifdef KADB
1301/*
1302 * C library -- reset, setexit -- XXX
1303 *
1304 *	reset(x)
1305 * will generate a "return" from
1306 * the last call to
1307 *	setexit()
1308 * by restoring r2 - r12, fp
1309 * and doing a return.
1310 * The returned value is x; on the original
1311 * call the returned value is 0.
1312 */
1313ENTRY(setexit, 0)
1314	movab	setsav,r0
1315	storer	$0x1ffc, (r0)
1316	movl	(fp),44(r0)		# fp
1317	moval	4(fp),48(r0)		# sp
1318	movl	-8(fp),52(r0)		# pc
1319	clrl	r0
1320	ret
1321
1322ENTRY(reset, 0)
1323	movl	4(fp),r0	# returned value
1324	movab	setsav,r1
1325	loadr	$0x1ffc,(r1)
1326	movl	44(r1),fp
1327	movl	48(r1),sp
1328	jmp 	*52(r1)
1329
1330	.data
1331	.align	2
1332setsav:	.space	14*4
1333	.text
1334#endif
1335
1336	.globl	_whichqs
1337	.globl	_qs
1338	.globl	_cnt
1339
1340	.globl	_noproc
1341	.comm	_noproc,4
1342	.globl	_runrun
1343	.comm	_runrun,4
1344/*
1345 * The following primitives use the fancy TAHOE instructions.
1346 * _whichqs tells which of the 32 queues _qs
1347 * have processes in them.  setrq puts processes into queues, remrq
1348 * removes them from queues.  The running process is on no queue,
1349 * other processes are on a queue related to p->p_pri, divided by 4
1350 * actually to shrink the 0-127 range of priorities into the 32 available
1351 * queues.
1352 */
1353
1354/*
1355 * setrq(p), using fancy TAHOE instructions.
1356 *
1357 * Call should be made at spl8(), and p->p_stat should be SRUN
1358 */
1359ENTRY(setrq, 0)
1360	movl	4(fp),r0
1361	tstl	P_RLINK(r0)		## firewall: p->p_rlink must be 0
1362	beql	set1			##
1363	pushab	set3			##
1364	callf	$8,_panic		##
1365set1:
1366	movzbl	P_PRI(r0),r1		# put on queue which is p->p_pri / 4
1367	shar	$2,r1,r1
1368	shal	$1,r1,r2
1369	moval	_qs[r2],r2
1370	insque	(r0),*4(r2)		# at end of queue
1371	shal	r1,$1,r1
1372	orl2	r1,_whichqs		# mark queue non-empty
1373	ret
1374
1375set3:	.asciz	"setrq"
1376
1377/*
1378 * remrq(p), using fancy TAHOE instructions
1379 *
1380 * Call should be made at spl8().
1381 */
1382ENTRY(remrq, 0)
1383	movl	4(fp),r0
1384	movzbl	P_PRI(r0),r1
1385	shar	$2,r1,r1
1386	bbs	r1,_whichqs,rem1
1387	pushab	rem3			# it wasn't recorded to be on its q
1388	callf	$8,_panic
1389rem1:
1390	remque	(r0)
1391	bneq	rem2			# q not empty yet
1392	shal	r1,$1,r1
1393	mcoml	r1,r1
1394	andl2	r1,_whichqs		# mark queue empty
1395rem2:
1396	clrl	P_RLINK(r0)		## for firewall checking
1397	ret
1398
1399rem3:	.asciz	"remrq"
1400
1401/*
1402 * Masterpaddr is the p->p_addr of the running process on the master
1403 * processor.  When a multiprocessor system, the slave processors will have
1404 * an array of slavepaddr's.
1405 */
1406	.globl	_masterpaddr
1407	.data
1408	.align	2
1409_masterpaddr: .long	0
1410
1411	.text
1412sw0:	.asciz	"swtch"
1413
1414/*
1415 * When no processes are on the runq, swtch branches to idle
1416 * to wait for something to come ready.
1417 */
1418	.globl  Idle
1419Idle: idle:
1420	movl	$1,_noproc
1421	mtpr	$0,$IPL			# must allow interrupts here
14221:
1423	tstl	_whichqs		# look for non-empty queue
1424	bneq	sw1
1425	brb	1b
1426
1427badsw:	pushab	sw0
1428	callf	$8,_panic
1429	/* NOTREACHED */
1430
1431	.align	2
1432/*
1433 * swtch(), using fancy tahoe instructions
1434 */
1435ENTRY(swtch, 0)
1436	movl	(fp),fp			# prepare for rei
1437	movl	(sp),4(sp)		# saved pc
1438	tstl	(sp)+
1439	movpsl	4(sp)
1440	incl	_cnt+V_SWTCH
1441sw1:	ffs	_whichqs,r0		# look for non-empty queue
1442	blss	idle			# if none, idle
1443	mtpr	$0x18,$IPL		# lock out all so _whichqs==_qs
1444	bbc	r0,_whichqs,sw1		# proc moved via interrupt
1445	shal	$1,r0,r1
1446	moval	_qs[r1],r1
1447	movl	(r1),r2			# r2 = p = highest pri process
1448	remque	*(r1)
1449	bvs	badsw			# make sure something was there
1450	bneq	sw2
1451	shal	r0,$1,r1
1452	mcoml	r1,r1
1453	andl2	r1,_whichqs		# no more procs in this queue
1454sw2:
1455	clrl	_noproc
1456	clrl	_runrun
1457#ifdef notdef
1458	tstl	P_WCHAN(r2)		## firewalls
1459	bneq	badsw			##
1460	cmpb	P_STAT(r2),$SRUN	##
1461	bneq	badsw			##
1462#endif
1463	clrl	P_RLINK(r2)		##
1464	movl	*P_ADDR(r2),r0
1465#ifdef notdef
1466	cmpl	r0,_masterpaddr		# resume of current proc is easy
1467	beql	res0
1468#endif
1469	movl	r0,_masterpaddr
1470	shal	$PGSHIFT,r0,r0		# r0 = pcbb(p)
1471	brb	swresume
1472
1473/*
1474 * resume(pf)
1475 */
1476ENTRY(resume, 0)
1477	shal	$PGSHIFT,4(fp),r0	# r0 = pcbb(pf)
1478	movl	(fp),fp			# prepare for rei
1479	movl	(sp)+,4(sp)		# saved pc
1480	tstl	(sp)+
1481	movpsl	4(sp)
1482swresume:
1483	mtpr	$0x18,$IPL		# no interrupts, please
1484	movl	_CMAP2,_u+PCB_CMAP2	# yech
1485	REST_ACC			# restore original accumulator
1486	svpctx
1487	mtpr	r0,$PCBB
1488	ldpctx
1489	movl	_u+PCB_CMAP2,_CMAP2	# yech
1490	mtpr	$_CADDR2,$TBIS
1491res0:
1492	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1493	tstl	P_CKEY(r2)		# does proc have code key?
1494	bneq	1f
1495	callf	$4,_getcodekey		# no, give him one
1496	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1497	movl	r0,P_CKEY(r2)
14981:
1499	tstl	P_DKEY(r2)		# does proc have data key?
1500	bneq	1f
1501	callf	$4,_getdatakey		# no, give him one
1502	movl	_u+U_PROCP,r2		# r2 = u.u_procp
1503	movl	r0,P_DKEY(r2)
15041:
1505	mtpr	P_CKEY(r2),$CCK		# set code cache key
1506	mtpr	P_DKEY(r2),$DCK		# set data cache key
1507	tstl	_u+PCB_SSWAP
1508	bneq	res1
1509	rei
1510res1:					# restore alternate saved context
1511	movl	_u+PCB_SSWAP,r2
1512	clrl	_u+PCB_SSWAP
1513	loadr	$0x3ff8,(r2); addl2 $44,r2	# restore r3-r13 (r13=fp)
1514	movl	(r2),r1; addl2 $4,r2	# fetch previous sp ...
1515	movab	(sp),r0			# ... and current sp and
1516	cmpl	r1,r0			# check for credibility,
1517	bgequ	1f			# if further up stack ...
1518	pushab 2f; callf $8,_panic	# ... panic
1519	/*NOTREACHED*/
15201:					# sp ok, complete return
1521	movl	r1,sp			# restore sp
1522	pushl	$PSL_PRVMOD		# kernel mode, ipl 0
1523	pushl	(r2)			# return address
1524	rei
15252:	.asciz	"ldctx"
1526
1527/*
1528 * {fu,su},{byte,word}
1529 */
1530ENTRY(fuword, 0)
1531	movl	4(fp), r1
1532	prober	$1,(r1),$4		# check access
1533	beql	fserr			# page unreadable
1534	bitl	$1,r1			# check byte alignment
1535	bneq	2f			# odd, do byte-word-byte
1536	bitl	$2,r1			# check word alignment
1537	bneq	1f			# odd, do in 2 words
1538	movl	(r1),r0			# move longword
1539	ret
15401:
1541	movw	(r1),r0			# move two words
1542	shal	$16,r0,r0
1543	movzwl	2(r1),r1		# orw2 sign extends
1544	orl2	r1,r0
1545	ret
15462:
1547	movb	(r1),r0			# move byte-word-byte
1548	shal	$24,r0,r0
1549	movzwl	1(r1),r2		# orw2 sign extends
1550	shal	$8,r2,r2
1551	movzbl	3(r1),r1		# orb2 sign extends
1552	orl2	r2,r1
1553	orl2	r1,r0
1554	ret
1555fserr:
1556	mnegl	$1,r0
1557	ret
1558
1559ENTRY(fubyte, 0)
1560	prober	$1,*4(fp),$1
1561	beql	fserr
1562	movzbl	*4(fp),r0
1563	ret
1564
1565ENTRY(suword, 0)
1566	movl	4(fp), r0
1567	probew	$1,(r0),$4		# check access
1568	beql	fserr			# page unwritable
1569	bitl	$1,r0			# check byte alignment
1570	bneq	1f			# odd byte boundary
1571	bitl	$2,r0			# check word alignment
1572	beql	2f			# longword aligned
1573	movw	8(fp),(r0)		# move two words
1574	movw	10(fp),2(r0)
1575	jbr	3f
15761:
1577	movb	8(fp),(r0)
1578	movb	9(fp),1(r0)
1579	movb	10(fp),2(r0)
1580	movb	11(fp),3(r0)
1581	jbr	3f
15822:
1583	movl	8(fp),(r0)
15843:
1585	clrl	r0
1586	ret
1587
1588ENTRY(subyte, 0)
1589	probew	$1,*4(fp),$1
1590	beql	fserr
1591	movb	11(fp),*4(fp)
1592	clrl	r0
1593	ret
1594
1595/*
1596 * Copy 1 relocation unit (NBPG bytes)
1597 * from user virtual address to physical address
1598 */
1599ENTRY(copyseg, 0)
1600	orl3	$PG_V|PG_KW,8(fp),_CMAP2
1601	mtpr	$_CADDR2,$TBIS	# invalidate entry for copy
1602	MOVC3(4(fp),$_CADDR2,$NBPG)
1603	ret
1604
1605/*
1606 * Clear a page of memory.  The page frame is specified.
1607 *
1608 * clearseg(pf);
1609 */
1610ENTRY(clearseg, 0)
1611	orl3	$PG_V|PG_KW,4(fp),_CMAP1	# Maps to virtual addr CADDR1
1612	mtpr	$_CADDR1,$TBIS
1613	movl	$255,r0				# r0 = limit
1614	clrl	r1				# r1 = index of cleared long
16151:
1616	clrl	_CADDR1[r1]
1617	aobleq	r0,r1,1b
1618	ret
1619
1620/*
1621 * Check user mode read/write access.
1622 *
1623 * useracc(addr, count, mode)
1624 *	caddr_t addr; int count, mode;
1625 * mode = 0	write access
1626 * mode = 1	read access
1627 */
1628ENTRY(useracc, 0)
1629	movl	$1,r2			# r2 = 'user mode' for probew/probew
1630probes:
1631	movl	4(fp),r0		# get va
1632	movl	8(fp),r1		# count
1633	tstl	12(fp)			# test for read access ?
1634	bneq	userar			# yes
1635	cmpl	$(CLSIZE*NBPG),r1	# can we do it in one probe ?
1636	bgeq	uaw2			# yes
1637uaw1:
1638	probew	r2,(r0),$(CLSIZE*NBPG)
1639	beql	uaerr			# no access
1640	addl2	$(CLSIZE*NBPG),r0
1641	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1)
1642uaw2:
1643	probew	r2,(r0),r1
1644	beql	uaerr
1645	movl	$1,r0
1646	ret
1647userar:
1648	cmpl	$(CLSIZE*NBPG),r1
1649	bgeq	uar2
1650uar1:
1651	prober	r2,(r0),$(CLSIZE*NBPG)
1652	beql	uaerr
1653	addl2	$(CLSIZE*NBPG),r0
1654	_ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1)
1655uar2:
1656	prober	r2,(r0),r1
1657	beql	uaerr
1658	movl	$1,r0
1659	ret
1660uaerr:
1661	clrl	r0
1662	ret
1663
1664/*
1665 * Check kernel mode read/write access.
1666 *
1667 * kernacc(addr, count, mode)
1668 *	caddr_t addr; int count, mode;
1669 * mode = 0	write access
1670 * mode = 1	read access
1671 */
1672ENTRY(kernacc, 0)
1673	clrl	r2		# r2 = 0 means kernel mode probe.
1674	jbr	probes		# Dijkstra would get gastric distress here.
1675
1676/*
1677 * addupc - increment some histogram counter
1678 *	in the profiling buffer
1679 *
1680 * addupc(pc, prof, delta)
1681 *	long pc; short delta; struct uprof *prof;
1682 *
1683 * struct uprof {		# profile arguments
1684 * 	short	*r_base;	# buffer base
1685 * 	unsigned pr_size;	# buffer size
1686 * 	unsigned pr_off;	# pc offset
1687 * 	unsigned pr_scale;	# pc scaling
1688 * }
1689 */
1690ENTRY(addupc, 0)
1691	movl	8(fp),r2		# r2 points to structure
1692	subl3	8(r2),4(fp),r0		# r0 = PC - lowpc
1693	jlss	9f			# PC < lowpc , out of range !
1694	shrl	$1,r0,r0		# the unit is words
1695	shrl	$1,12(r2),r1		# ditto for scale
1696	emul	r1,r0,$0,r0
1697	shrq	$14,r0,r0
1698	tstl	r0			# too big
1699	jneq	9f
1700	cmpl	r1,4(r2)		# Check buffer overflow
1701	jgequ	9f
1702	probew	$1,*0(r2)[r1],$2	# counter accessible?
1703	jeql	9f
1704	shrl	$1,r1,r1		# make r1 word index
1705	addw2	14(fp),*0(r2)[r1]
17069:	ret
1707
1708/*
1709 * scanc(size, cp, table, mask)
1710 */
1711ENTRY(scanc, R3|R4)
1712	movl	8(fp),r0		# r0 = cp
1713	addl3	4(fp),r0,r2		# end = &cp[size]
1714	movl	12(fp),r1		# r1 = table
1715	movb	19(fp),r4		# r4 = mask
1716	decl	r0			# --cp
1717	jbr	0f			# just like Fortran...
17181:					# do {
1719	movzbl	(r0),r3
1720	bitb	r4,(r1)[r3]		#	if (table[*cp] & mask)
1721	jneq	2f			#		break;
17220:	aoblss	r2,r0,1b		# } while (++cp < end);
17232:
1724	subl3	r0,r2,r0; ret		# return (end - cp);
1725
1726/*
1727 * skpc(mask, size, cp)
1728 */
1729ENTRY(skpc, 0)
1730	movl	12(fp),r0		# r0 = cp
1731	addl3	8(fp),r0,r1		# r1 = end = &cp[size];
1732	movb	7(fp),r2		# r2 = mask
1733	decl	r0			# --cp;
1734	jbr	0f
17351:					# do
1736	cmpb	(r0),r2			#	if (*cp != mask)
1737	jneq	2f			#		break;
17380:	aoblss	r1,r0,1b		# while (++cp < end);
17392:
1740	subl3	r0,r1,r0; ret		# return (end - cp);
1741
1742/*
1743 * locc(mask, size, cp)
1744 */
1745ENTRY(locc, 0)
1746	movl	12(fp),r0		# r0 = cp
1747	addl3	8(fp),r0,r1		# r1 = end = &cp[size]
1748	movb	7(fp),r2		# r2 = mask
1749	decl	r0			# --cp;
1750	jbr	0f
17511:					# do
1752	cmpb	(r0),r2			#	if (*cp == mask)
1753	jeql	2f			#		break;
17540:	aoblss	r1,r0,1b		# while (++cp < end);
17552:
1756	subl3	r0,r1,r0; ret		# return (end - cp);
1757
1758#ifdef ALIGN
1759#include "tahoe/align/align.h"
1760
1761	.globl	_alignment
1762/*
1763 * There's an intimate relationship between this piece of code
1764 * and the alignment emulation code (especially the layout
1765 * of local variables in alignment.c! Don't change unless
1766 * you update both this, alignment.h and alignment.c !!
1767 */
1768non_aligned:
1769	orb2	$EMULATEALIGN,_u+U_EOSYS
1770	incl	_cnt+V_TRAP
1771	incl	_cnt+V_ALIGN		# count emulated alignment traps
1772	moval	4(sp),_user_psl
1773	SAVE_FPSTAT(4)			# Also zeroes out ret_exception !
1774	pushl	$0			# ret_addr
1775	pushl	$0			# ret_code
1776	mfpr	$USP,-(sp)		# user sp
1777	callf	$4,_alignment		# call w/o parms so regs may be modified
1778	/*
1779	 * We return here after a successful emulation or an exception.
1780	 * The registers have been restored and we must not alter them
1781	 * before returning to the user.
1782	 */
17832:	mtpr	(sp)+,$USP		# restore user sp
1784	tstl	8(sp)			# Any exception ?
1785	bneq	got_excp		# Yes, reflect it back to user.
1786	moval	8(sp),sp		# pop 2 zeroes pushed above
1787	REST_FPSTAT
1788	xorb2	$EMULATEALIGN,_u+U_EOSYS
1789
1790	bitl	$PSL_T,4(sp)		# check for trace bit set
1791	beql	9f
1792	CHECK_SFE(4)
1793	pushl $0
1794	SAVE_FPSTAT(8)
1795	TRAP(TRCTRAP)
17969:	rei
1797
1798got_excp:				# decode exception
1799	casel	8(sp),$ILL_ADDRMOD,$ALIGNMENT
1800	.align	1
1801L1:
1802	.word	ill_addrmod-L1
1803	.word	ill_access-L1
1804	.word	ill_oprnd-L1
1805	.word	arithmetic-L1
1806	.word	alignment-L1
1807	brw	alignment		# default - shouldn't come here at all !
1808
1809ill_addrmod:				# No other parameters. Set up stack as
1810	moval	8(sp),sp		# the HW would do it in a real case.
1811	REST_FPSTAT
1812	jbr	_Xresadflt
1813ill_oprnd:
1814	moval	8(sp),sp
1815	REST_FPSTAT
1816	jbr	_Xresopflt
1817alignment:
1818	moval	8(sp),sp
1819	REST_FPSTAT
1820	jbr	align_excp	# NB: going to _Xalignflt would cause loop
1821ill_access:
1822	/*
1823	 * Must restore accumulator w/o modifying sp and w/o using
1824	 * registers.  Solution: copy things needed by REST_FPSTAT.
1825	 */
1826	pushl	20(sp)			# The flags longword
1827	pushl	20(sp)			# acc_low
1828	pushl	20(sp)			# acc_high
1829	pushl	20(sp)			# ret_exception ignored by REST_FPSTAT
1830	REST_FPSTAT			# Back where we were with the sp !
1831	movl	(sp),16(sp)		# code for illegal access
1832	movl	4(sp),20(sp)		# original virtual address
1833	moval	16(sp),sp		# Just like the HW would set it up
1834	jbr	_Xprotflt
1835arithmetic:				# same trickery as above
1836	pushl	20(sp)			# The flags longword
1837	pushl	20(sp)			# acc_low
1838	pushl	20(sp)			# acc_high
1839	pushl	20(sp)			# ret_exception ignored by REST_FPSTAT
1840	REST_FPSTAT			# Back where we were with the sp !
1841	movl	(sp),20(sp)		# code for arithmetic exception
1842	moval	20(sp),sp		# Just like the HW would set it up
1843	jbr	_Xarithtrap
1844#endif
1845