xref: /original-bsd/sys/luna68k/luna68k/locore.s (revision daedb501)
1/*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1992 OMRON Corporation.
4 * Copyright (c) 1980, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department.
10 *
11 * %sccs.include.redist.c%
12 *
13 * from: Utah $Hdr: locore.s 1.62 92/01/20$
14 * OMRON: $Id: locore.s,v 1.2 92/06/14 06:16:34 moti Exp $
15 *
16 * from: hp300/hp300/locore.s   7.16 (Berkeley) 7/8/92
17 *
18 *	@(#)locore.s	7.3 (Berkeley) 07/23/92
19 */
20
21#include "assym.s"
22#include "vectors.s"
23
24	.text
25/*
26 * This is where we wind up if the kernel jumps to location 0.
27 * (i.e. a bogus PC)  This is known to immediately follow the vector
28 * table and is hence at 0x400 (see reset vector in vectors.s).
29 */
30	.globl	_panic
31	pea	Ljmp0panic
32	jbsr	_panic
33	/* NOTREACHED */
34Ljmp0panic:
35	.asciz	"kernel jump to zero"
36	.even
37
38/*
39 * Do a dump.
40 * Called by auto-restart.
41 */
42	.globl	_dumpsys
43	.globl	_doadump
44_doadump:
45	jbsr	_dumpsys
46	jbsr	_doboot
47	/*NOTREACHED*/
48
49/*
50 * Trap/interrupt vector routines
51 */
52
53	.globl	_trap, _nofault, _longjmp
54_buserr:
55	tstl	_nofault		| device probe?
56	jeq	_addrerr		| no, handle as usual
57	movl	_nofault,sp@-		| yes,
58	jbsr	_longjmp		|  longjmp(nofault)
59_addrerr:
60	clrw	sp@-			| pad SR to longword
61	moveml	#0xFFFF,sp@-		| save user registers
62	movl	usp,a0			| save the user SP
63	movl	a0,sp@(60)		|   in the savearea
64	lea	sp@(64),a1		| grab base of HW berr frame
65	moveq	#0,d0
66	movw	a1@(12),d0		| grab SSW for fault processing
67	btst	#12,d0			| RB set?
68	jeq	LbeX0			| no, test RC
69	bset	#14,d0			| yes, must set FB
70	movw	d0,a1@(12)		| for hardware too
71LbeX0:
72	btst	#13,d0			| RC set?
73	jeq	LbeX1			| no, skip
74	bset	#15,d0			| yes, must set FC
75	movw	d0,a1@(12)		| for hardware too
76LbeX1:
77	btst	#8,d0			| data fault?
78	jeq	Lbe0			| no, check for hard cases
79	movl	a1@(18),d1		| fault address is as given in frame
80	jra	Lbe10			| thats it
81Lbe0:
82	btst	#4,a1@(8)		| long (type B) stack frame?
83	jne	Lbe4			| yes, go handle
84	movl	a1@(4),d1		| no, can use save PC
85	btst	#14,d0			| FB set?
86	jeq	Lbe3			| no, try FC
87	addql	#4,d1			| yes, adjust address
88	jra	Lbe10			| done
89Lbe3:
90	btst	#15,d0			| FC set?
91	jeq	Lbe10			| no, done
92	addql	#2,d1			| yes, adjust address
93	jra	Lbe10			| done
94Lbe4:
95	movl	a1@(38),d1		| long format, use stage B address
96	btst	#15,d0			| FC set?
97	jeq	Lbe10			| no, all done
98	subql	#2,d1			| yes, adjust address
99Lbe10:
100	movl	d1,sp@-			| push fault VA
101	movl	d0,sp@-			| and padded SSW
102	movw	a1@(8),d0		| get frame format/vector offset
103	andw	#0x0FFF,d0		| clear out frame format
104	cmpw	#12,d0			| address error vector?
105	jeq	Lisaerr			| yes, go to it
106	movl	d1,a0			| fault address
107	ptestr	#1,a0@,#7		| do a table search
108	pmove	psr,sp@			| save result
109	btst	#7,sp@			| bus error bit set?
110	jeq	Lismerr			| no, must be MMU fault
111	clrw	sp@			| yes, re-clear pad word
112	jra	Lisberr			| and process as normal bus error
113Lismerr:
114	movl	#T_MMUFLT,sp@-		| show that we are an MMU fault
115	jra	Ltrapnstkadj		| and deal with it
116Lisaerr:
117	movl	#T_ADDRERR,sp@-		| mark address error
118	jra	Ltrapnstkadj		| and deal with it
119Lisberr:
120	movl	#T_BUSERR,sp@-		| mark bus error
121Ltrapnstkadj:
122	jbsr	_trap			| handle the error
123	lea	sp@(12),sp		| pop value args
124	movl	sp@(60),a0		| restore user SP
125	movl	a0,usp			|   from save area
126	movw	sp@(64),d0		| need to adjust stack?
127	jne	Lstkadj			| yes, go to it
128	moveml	sp@+,#0x7FFF		| no, restore most user regs
129	addql	#6,sp			| toss SSP and pad
130	jra	rei			| all done
131Lstkadj:
132	lea	sp@(66),a1		| pointer to HW frame
133	addql	#8,a1			| source pointer
134	movl	a1,a0			| source
135	addw	d0,a0			|  + hole size = dest pointer
136	movl	a1@-,a0@-		| copy
137	movl	a1@-,a0@-		|  8 bytes
138	movl	a0,sp@(60)		| new SSP
139	moveml	sp@+,#0x7FFF		| restore user registers
140	movl	sp@,sp			| and our SP
141	jra	rei			| all done
142
143/*
144 * FP exceptions.
145 */
146_fpfline:
147	jra	_illinst
148
149_fpunsupp:
150	jra	_illinst
151
152/*
153 * Handles all other FP coprocessor exceptions.
154 * Note that since some FP exceptions generate mid-instruction frames
155 * and may cause signal delivery, we need to test for stack adjustment
156 * after the trap call.
157 */
158_fpfault:
159#ifdef FPCOPROC
160	clrw	sp@-		| pad SR to longword
161	moveml	#0xFFFF,sp@-	| save user registers
162	movl	usp,a0		| and save
163	movl	a0,sp@(60)	|   the user stack pointer
164	clrl	sp@-		| no VA arg
165	movl	_curpcb,a0	| current pcb
166	lea	a0@(PCB_FPCTX),a0 | address of FP savearea
167	fsave	a0@		| save state
168	tstb	a0@		| null state frame?
169	jeq	Lfptnull	| yes, safe
170	clrw	d0		| no, need to tweak BIU
171	movb	a0@(1),d0	| get frame size
172	bset	#3,a0@(0,d0:w)	| set exc_pend bit of BIU
173Lfptnull:
174	fmovem	fpsr,sp@-	| push fpsr as code argument
175	frestore a0@		| restore state
176	movl	#T_FPERR,sp@-	| push type arg
177	jra	Ltrapnstkadj	| call trap and deal with stack cleanup
178#else
179	jra	_badtrap	| treat as an unexpected trap
180#endif
181
182/*
183 * Coprocessor and format errors can generate mid-instruction stack
184 * frames and cause signal delivery hence we need to check for potential
185 * stack adjustment.
186 */
187_coperr:
188	clrw	sp@-
189	moveml	#0xFFFF,sp@-
190	movl	usp,a0		| get and save
191	movl	a0,sp@(60)	|   the user stack pointer
192	clrl	sp@-		| no VA arg
193	clrl	sp@-		| or code arg
194	movl	#T_COPERR,sp@-	| push trap type
195	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
196
197_fmterr:
198	clrw	sp@-
199	moveml	#0xFFFF,sp@-
200	movl	usp,a0		| get and save
201	movl	a0,sp@(60)	|   the user stack pointer
202	clrl	sp@-		| no VA arg
203	clrl	sp@-		| or code arg
204	movl	#T_FMTERR,sp@-	| push trap type
205	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
206
207/*
208 * Other exceptions only cause four and six word stack frame and require
209 * no post-trap stack adjustment.
210 */
211_illinst:
212	clrw	sp@-
213	moveml	#0xFFFF,sp@-
214	moveq	#T_ILLINST,d0
215	jra	fault
216
217_zerodiv:
218	clrw	sp@-
219	moveml	#0xFFFF,sp@-
220	moveq	#T_ZERODIV,d0
221	jra	fault
222
223_chkinst:
224	clrw	sp@-
225	moveml	#0xFFFF,sp@-
226	moveq	#T_CHKINST,d0
227	jra	fault
228
229_trapvinst:
230	clrw	sp@-
231	moveml	#0xFFFF,sp@-
232	moveq	#T_TRAPVINST,d0
233	jra	fault
234
235_privinst:
236	clrw	sp@-
237	moveml	#0xFFFF,sp@-
238	moveq	#T_PRIVINST,d0
239	jra	fault
240
241	.globl	fault
242fault:
243	movl	usp,a0			| get and save
244	movl	a0,sp@(60)		|   the user stack pointer
245	clrl	sp@-			| no VA arg
246	clrl	sp@-			| or code arg
247	movl	d0,sp@-			| push trap type
248	jbsr	_trap			| handle trap
249	lea	sp@(12),sp		| pop value args
250	movl	sp@(60),a0		| restore
251	movl	a0,usp			|   user SP
252	moveml	sp@+,#0x7FFF		| restore most user regs
253	addql	#6,sp			| pop SP and pad word
254	jra	rei			| all done
255
256	.globl	_straytrap
257_badtrap:
258	clrw	sp@-			| pad SR
259	moveml	#0xC0C0,sp@-		| save scratch regs
260	movw	sp@(24),sp@-		| push exception vector info
261	clrw	sp@-
262	movl	sp@(24),sp@-		| and PC
263	jbsr	_straytrap		| report
264	addql	#8,sp			| pop args
265	moveml	sp@+,#0x0303		| restore regs
266	addql	#2,sp			| pop padding
267	jra	rei			| all done
268
269	.globl	_syscall
270_trap0:
271	clrw	sp@-			| pad SR to longword
272	moveml	#0xFFFF,sp@-		| save user registers
273	movl	usp,a0			| save the user SP
274	movl	a0,sp@(60)		|   in the savearea
275	movl	d0,sp@-			| push syscall number
276	jbsr	_syscall		| handle it
277	addql	#4,sp			| pop syscall arg
278	movl	sp@(60),a0		| grab and restore
279	movl	a0,usp			|   user SP
280	moveml	sp@+,#0x7FFF		| restore most registers
281	addql	#6,sp			| pop SSP and align word
282	jra	rei			| all done
283
284/*
285 * trap1 is sigreturn and trap2 is breakpoint.
286 */
287_trap1:
288	jra	sigreturn		| trap1 is sigreturn
289
290_trap2:
291	jra	_trace			| trap2 is breakpoint
292
293/*
294 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
295 *	cachectl(command, addr, length)
296 * command in d0, addr in a1, length in d1
297 */
298	.globl	_cachectl
299_trap12:
300	movl	d1,sp@-			| push length
301	movl	a1,sp@-			| push addr
302	movl	d0,sp@-			| push command
303	jbsr	_cachectl		| do it
304	lea	sp@(12),sp		| pop args
305	jra	rei			| all done
306
307/*
308 * Trap 15 is used for:
309 *	- KGDB traps
310 *	- trace traps for SUN binaries (not fully supported yet)
311 * We just pass it on and let trap() sort it all out
312 */
313_trap15:
314	clrw	sp@-
315	moveml	#0xFFFF,sp@-
316#ifdef KGDB
317	moveq	#T_TRAP15,d0
318	movl	sp@(64),d1		| from user mode?
319	andl	#PSL_S,d1
320	jeq	fault
321	movl	d0,sp@-
322	.globl	_kgdb_trap_glue
323	jbsr	_kgdb_trap_glue		| returns if no debugger
324	addl	#4,sp
325#endif
326	moveq	#T_TRAP15,d0
327	jra	fault
328
329/*
330 * Hit a breakpoint (trap 1 or 2) instruction.
331 * Push the code and treat as a normal fault.
332 */
333_trace:
334	clrw	sp@-
335	moveml	#0xFFFF,sp@-
336#ifdef KGDB
337	moveq	#T_TRACE,d0
338	movl	sp@(64),d1		| from user mode?
339	andl	#PSL_S,d1
340	jeq	fault
341	movl	d0,sp@-
342	jbsr	_kgdb_trap_glue		| returns if no debugger
343	addl	#4,sp
344#endif
345	moveq	#T_TRACE,d0
346	jra	fault
347
348/*
349 * The sigreturn() syscall comes here.  It requires special handling
350 * because we must open a hole in the stack to fill in the (possibly much
351 * larger) original stack frame.
352 */
353sigreturn:
354	lea	sp@(-84),sp		| leave enough space for largest frame
355	movl	sp@(84),sp@		| move up current 8 byte frame
356	movl	sp@(88),sp@(4)
357	movw	#84,sp@-		| default: adjust by 84 bytes
358	moveml	#0xFFFF,sp@-		| save user registers
359	movl	usp,a0			| save the user SP
360	movl	a0,sp@(60)		|   in the savearea
361	movl	#SYS_sigreturn,sp@-	| push syscall number
362	jbsr	_syscall		| handle it
363	addql	#4,sp			| pop syscall#
364	movl	sp@(60),a0		| grab and restore
365	movl	a0,usp			|   user SP
366	lea	sp@(64),a1		| pointer to HW frame
367	movw	a1@+,d0			| do we need to adjust the stack?
368	jeq	Lsigr1			| no, just continue
369	moveq	#92,d1			| total size
370	subw	d0,d1			|  - hole size = frame size
371	lea	a1@(92),a0		| destination
372	addw	d1,a1			| source
373	lsrw	#1,d1			| convert to word count
374	subqw	#1,d1			| minus 1 for dbf
375Lsigrlp:
376	movw	a1@-,a0@-		| copy a word
377	dbf	d1,Lsigrlp		| continue
378	movl	a0,a1			| new HW frame base
379Lsigr1:
380	movl	a1,sp@(60)		| new SP value
381	moveml	sp@+,#0x7FFF		| restore user registers
382	movl	sp@,sp			| and our SP
383	jra	rei			| all done
384
385/*
386 * Interrupt handlers.
387 * All DIO device interrupts are auto-vectored.  Most can be configured
388 * to interrupt in the range IPL2 to IPL5.  Here are our assignments:
389 *
390 *	Level 0:	Spurious: ignored.
391 *	Level 1:	(low XP)
392 *	Level 2:	SCSI
393 *	Level 3:	LANCE
394 *	Level 4:	[PC98]
395 *	Level 5:	Clock
396 *	Level 6:	RS232C
397 *	Level 7:	Non-maskable: parity errors, Abort SW
398 */
399	.globl	_hardclock, _nmihand
400
401_spurintr:
402	addql	#1,_intrcnt+0
403	addql	#1,_cnt+V_INTR
404	jra	rei
405
406_lev1intr:
407	addql	#1,_intrcnt+4
408	addql	#1,_cnt+V_INTR
409	jra	rei			| XP not surpported yet	XXXX
410
411_lev2intr:
412	addql	#1,_intrcnt+8
413	clrw	sp@-
414	moveml	#0xC0C0,sp@-
415	jbsr	__scintr
416	moveml	sp@+,#0x0303
417	addql	#2,sp
418	addql	#1,_cnt+V_INTR
419	jra	rei
420
421_lev3intr:
422	addql	#1,_intrcnt+12
423	clrw	sp@-
424	moveml	#0xC0C0,sp@-
425	jbsr	__leintr
426	moveml	sp@+,#0x0303
427	addql	#2,sp
428	addql	#1,_cnt+V_INTR
429	jra	rei
430
431_lev4intr:
432	addql	#1,_intrcnt+16
433	addql	#1,_cnt+V_INTR
434	jra	rei			| EX-PC not surpported yet XXXX
435
436_lev6intr:
437	addql	#1,_intrcnt+24
438	clrw	sp@-
439	moveml	#0xC0C0,sp@-
440	jbsr	_siointr
441	moveml	sp@+,#0x0303
442	addql	#2,sp
443	addql	#1,_cnt+V_INTR
444	jra	rei
445
446_lev5intr:
447	clrw	sp@-
448	moveml	#0xC0C0,sp@-
449#ifdef DEBUG
450	.globl	_panicstr, _regdump, _panic
451	cmpl	#_kstack+NBPG,sp	| are we still in stack pages?
452	jcc	Lstackok		| yes, continue normally
453	tstl	_curproc		| if !curproc could have swtch_exit'ed,
454	jeq	Lstackok		|     might be on tmpstk
455	tstl	_panicstr		| have we paniced?
456	jne	Lstackok		| yes, do not re-panic
457	lea	tmpstk,sp		| no, switch to tmpstk
458	moveml	#0xFFFF,sp@-		| push all registers
459	movl	#Lstkrip,sp@-		| push panic message
460	jbsr	_printf			| preview
461	addql	#4,sp
462	movl	sp,a0			| remember this spot
463	movl	#256,sp@-		| longword count
464	movl	a0,sp@-			| and reg pointer
465	jbsr	_regdump		| dump core
466	addql	#8,sp			| pop params
467	movl	#Lstkrip,sp@-		| push panic message
468	jbsr	_panic			| ES and D
469Lstkrip:
470	.asciz	"k-stack overflow"
471	.even
472Lstackok:
473#endif
474	btst	#CLK_INT,CLOCK_REG 	| check system clock-intr
475	jeq	Lnottimer
476	movb	#CLK_CLR,CLOCK_REG	| clear system clock interrupt
477        tstl	_clock_on		| clock not yet started
478        jeq	Lnottimer
479	lea	sp@(16),a1		| get pointer to PS
480	movl	a1@,sp@-		| push padded PS
481	movl	a1@(4),sp@-		| push PC
482	jbsr	_hardclock		| call generic clock int routine
483	addql	#8,sp			| pop params
484Lnottimer:
485	addql	#1,_intrcnt+28		| add another system clock interrupt
486	moveml	sp@+,#0x0303		| restore scratch regs
487	addql	#2,sp			| pop pad word
488	addql	#1,_cnt+V_INTR		| chalk up another interrupt
489	jra	rei			| all done
490
491_lev7intr:
492	addql	#1,_intrcnt+36
493	clrw	sp@-			| pad SR to longword
494	moveml	#0xFFFF,sp@-		| save registers
495	movl	usp,a0			| and save
496	movl	a0,sp@(60)		|   the user stack pointer
497	jbsr	_nmihand		| call handler
498	movl	sp@(60),a0		| restore
499	movl	a0,usp			|   user SP
500	moveml	sp@+,#0x7FFF		| and remaining registers
501	addql	#6,sp			| pop SSP and align word
502	jra	rei			| all done
503
504/*
505 * Emulation of VAX REI instruction.
506 *
507 * This code deals with checking for and servicing ASTs
508 * (profiling, scheduling) and software interrupts (network, softclock).
509 * We check for ASTs first, just like the VAX.  To avoid excess overhead
510 * the T_ASTFLT handling code will also check for software interrupts so we
511 * do not have to do it here.
512 *
513 * This code is complicated by the fact that sendsig may have been called
514 * necessitating a stack cleanup.
515 */
516	.comm	_ssir,1
517	.globl	_astpending
518rei:
519#ifdef DEBUG
520	tstl	_panicstr		| have we paniced?
521	jne	Ldorte			| yes, do not make matters worse
522#endif
523	tstl	_astpending		| AST pending?
524	jeq	Lchksir			| no, go check for SIR
525Lrei1:
526	btst	#5,sp@			| yes, are we returning to user mode?
527	jne	Lchksir			| no, go check for SIR
528	clrw	sp@-			| pad SR to longword
529	moveml	#0xFFFF,sp@-		| save all registers
530	movl	usp,a1			| including
531	movl	a1,sp@(60)		|    the users SP
532	clrl	sp@-			| VA == none
533	clrl	sp@-			| code == none
534	movl	#T_ASTFLT,sp@-		| type == async system trap
535	jbsr	_trap			| go handle it
536	lea	sp@(12),sp		| pop value args
537	movl	sp@(60),a0		| restore user SP
538	movl	a0,usp			|   from save area
539	movw	sp@(64),d0		| need to adjust stack?
540	jne	Laststkadj		| yes, go to it
541	moveml	sp@+,#0x7FFF		| no, restore most user regs
542	addql	#6,sp			| toss SSP and pad
543	rte				| and do real RTE
544Laststkadj:
545	lea	sp@(66),a1		| pointer to HW frame
546	addql	#8,a1			| source pointer
547	movl	a1,a0			| source
548	addw	d0,a0			|  + hole size = dest pointer
549	movl	a1@-,a0@-		| copy
550	movl	a1@-,a0@-		|  8 bytes
551	movl	a0,sp@(60)		| new SSP
552	moveml	sp@+,#0x7FFF		| restore user registers
553	movl	sp@,sp			| and our SP
554	rte				| and return
555Lchksir:
556	tstb	_ssir			| SIR pending?
557	jeq	Ldorte			| no, all done
558	movl	d0,sp@-			| need a scratch register
559	movw	sp@(4),d0		| get SR
560	andw	#PSL_IPL7,d0		| mask all but IPL
561	jne	Lnosir			| came from interrupt, no can do
562	movl	sp@+,d0			| restore scratch register
563Lgotsir:
564	movw	#SPL1,sr		| prevent others from servicing int
565	tstb	_ssir			| too late?
566	jeq	Ldorte			| yes, oh well...
567	clrw	sp@-			| pad SR to longword
568	moveml	#0xFFFF,sp@-		| save all registers
569	movl	usp,a1			| including
570	movl	a1,sp@(60)		|    the users SP
571	clrl	sp@-			| VA == none
572	clrl	sp@-			| code == none
573	movl	#T_SSIR,sp@-		| type == software interrupt
574	jbsr	_trap			| go handle it
575	lea	sp@(12),sp		| pop value args
576	movl	sp@(60),a0		| restore
577	movl	a0,usp			|   user SP
578	moveml	sp@+,#0x7FFF		| and all remaining registers
579	addql	#6,sp			| pop SSP and align word
580	rte
581Lnosir:
582	movl	sp@+,d0			| restore scratch register
583Ldorte:
584	rte				| real return
585
586/*
587 * Kernel access to the current processes kernel stack is via a fixed
588 * virtual address.  It is at the same address as in the users VA space.
589 * Umap contains the KVA of the first of UPAGES PTEs mapping VA _kstack.
590 */
591	.data
592	.set	_kstack,KERNELSTACK	| KERNELSTACK(0x3ff00000) != USRSTACK
593_Umap:	.long	0
594	.globl	_kstack, _Umap
595
596/*
597 * Initialization
598 *
599 * Kernel is loaded at 0.
600 * VBR contains zero from ROM.  Exceptions will continue to vector
601 * through ROM until MMU is turned on at which time they will vector
602 * through our table (vectors.s).
603 */
604	.comm	_lowram,4
605
606	.text
607	.globl	_edata
608	.globl	_etext,_end
609	.globl	start
610start:
611	movw	#PSL_HIGHIPL,sr		| no interrupts
612	lea	tmpstk,sp		| give ourselves a temporary stack
613	clrl	d0			| XXXX if loader set vbr = 0
614	movc	d0,vbr			| XXXX please remove these 2 lines
615/*
616 * a5 contains parameters address from booter.
617 * First, we copy parameters to save area.
618 * (Now just save maxmem and so on. Not complete yet.) XXXX
619 */
620	movl	a5@(KI_MAXADDR),d0	| maxaddr
621	moveq	#PGSHIFT,d1
622	lsrl	d1,d0			| convert to page (click) number
623	movl	d0,_maxmem		| argument saved in maxmem
624	movl	d0,_physmem		| physmem = maxmem
625	clrl	_lowram			| lowram = 0
626	movl	#0,a5			| kernel is loaded at 0
627	movl	#CACHE_OFF,d0
628	movc	d0,cacr			| clear and disable on-chip cache(s)
629
630/* initialize source/destination control registers for movs */
631	moveq	#FC_USERD,d0		| user space
632	movc	d0,sfc			|   as source
633	movc	d0,dfc			|   and destination of transfers
634
635/*
636 * LUNA  PIO initialization.
637 */
638	movb	#PIO_MODED,PIO0_CTL	| read dipswitch
639	movb	PIO0_B,d0		| dipsw-2 (from portB)
640	lsll	#8,d0
641	movb	PIO0_A,d0		| dipsw-1 (from portA)
642	movw	d0,_dipswitch
643
644/* configure kernel and proc0 VA space so we can get going */
645	.globl	_Sysseg, _pmap_bootstrap, _avail_start
646	movl	#_end,d5		| end of static kernel text/data
647	addl	#NBPG-1,d5
648	andl	#PG_FRAME,d5		| round to a page
649	movl	d5,a4			| PA=VA
650	pea	a5@			| firstpa
651	pea	a4@			| nextpa
652	jbsr	_pmap_bootstrap		| bootstrap(firstpa, nextpa)
653	addql	#8,sp
654
655/*
656 * Prepare to enable MMU.
657 */
658	movl	_Sysseg,a1		| system segment table addr read value (a KVA)
659	lea	_protorp,a0
660	movl	#0x80000202,a0@		| nolimit + share global + 4 byte PTEs
661	movl	a1,a0@(4)		| + segtable address
662	pmove	a0@,srp			| load the supervisor root pointer
663	movl	#0x80000002,a0@		| reinit upper half for CRP loads
664/* we must set tt-registers here */
665	lea	_protott0,a0
666	.word	0xf010			| pmove	a0@,mmutt0
667	.word	0x0800
668	lea	_protott1,a0
669	.word	0xf010			| pmove	a0@,mmutt1
670	.word	0x0c00
671	movl	#0x82c0aa00,a2@		| value to load TC with
672	pmove	a2@,tc			| load it
673
674/*
675 * Should be running mapped from this point on
676 */
677#ifdef FPCOPROC
678/* fpp check */
679	movl	a1,sp@-
680	jbsr	_checkfpp		| check fpp
681	frestore _fppnull		| reset
682	movl	sp@+,a1
683#endif
684/* select the software page size now */
685	lea	tmpstk,sp		| temporary stack
686	jbsr	_vm_set_page_size	| select software page size
687#ifdef BOOTDEBUG
688	movl	a5,sp@-			| phys load address (assumes VA 0)
689	movl	a4,sp@-			| first available PA
690	jbsr	_Opmap_bootstrap	| sync up pmap module
691	addql	#8,sp
692#endif
693/* set kernel stack, user SP, and initial pcb */
694	lea	_kstack,a1		| proc0 kernel stack
695	lea	a1@(UPAGES*NBPG-4),sp	| set kernel stack to end of area
696	movl	#USRSTACK-4,a2
697	movl	a2,usp			| init user SP
698	movl	_proc0paddr,a1		| get proc0 pcb addr
699	movl	a1,_curpcb		| proc0 is running
700	clrw	a1@(PCB_FLAGS)		| clear flags
701#ifdef FPCOPROC
702	clrl	a1@(PCB_FPCTX)		| ensure null FP context
703	movl	a1,sp@-
704	jbsr	_m68881_restore		| restore it (does not kill a1)
705	addql	#4,sp
706#endif
707/* flush TLB and turn on caches */
708	jbsr	_TBIA			| invalidate TLB
709	movl	#CACHE_ON,d0
710	movc	d0,cacr			| clear cache(s)
711/* final setup for C code */
712	movw	#PSL_LOWIPL,sr		| lower SPL
713	movl	d7,_boothowto		| save reboot flags
714	movl	d6,_bootdev		|   and boot device
715	jbsr	_main			| call main()
716
717/* proc[1] == init now running here;
718 * create a null exception frame and return to user mode in icode
719 */
720	clrw	sp@-			| vector offset/frame type
721	clrl	sp@-			| return to icode location 0
722	movw	#PSL_USER,sp@-		| in user mode
723	rte
724
725/*
726 * Signal "trampoline" code (18 bytes).  Invoked from RTE setup by sendsig().
727 *
728 * Stack looks like:
729 *
730 *	sp+0 ->	signal number
731 *	sp+4	signal specific code
732 *	sp+8	pointer to signal context frame (scp)
733 *	sp+12	address of handler
734 *	sp+16	saved hardware state
735 *			.
736 *			.
737 *	scp+0->	beginning of signal context frame
738 */
739	.globl	_sigcode, _esigcode
740	.data
741_sigcode:
742	movl	sp@(12),a0		| signal handler addr	(4 bytes)
743	jsr	a0@			| call signal handler	(2 bytes)
744	addql	#4,sp			| pop signo		(2 bytes)
745	trap	#1			| special syscall entry	(2 bytes)
746	movl	d0,sp@(4)		| save errno		(4 bytes)
747	moveq	#1,d0			| syscall == exit	(2 bytes)
748	trap	#0			| exit(errno)		(2 bytes)
749	.align	2
750_esigcode:
751
752/*
753 * Icode is copied out to process 1 to exec init.
754 * If the exec fails, process 1 exits.
755 */
756	.globl	_icode,_szicode
757	.text
758_icode:
759	clrl	sp@-
760	pea	pc@((argv-.)+2)
761	pea	pc@((init-.)+2)
762	clrl	sp@-
763	moveq	#SYS_execve,d0
764	trap	#0
765	moveq	#SYS_exit,d0
766	trap	#0
767init:
768	.asciz	"/sbin/init"
769	.even
770argv:
771	.long	init+6-_icode		| argv[0] = "init" ("/sbin/init" + 6)
772	.long	eicode-_icode		| argv[1] follows icode after copyout
773	.long	0
774eicode:
775
776_szicode:
777	.long	_szicode-_icode
778
779/*
780 * Primitives
781 */
782
783#ifdef GPROF
784#define	ENTRY(name) \
785	.globl _/**/name; _/**/name: link a6,#0; jbsr mcount; unlk a6
786#define ALTENTRY(name, rname) \
787	ENTRY(name); jra rname+12
788#else
789#define	ENTRY(name) \
790	.globl _/**/name; _/**/name:
791#define ALTENTRY(name, rname) \
792	.globl _/**/name; _/**/name:
793#endif
794
795/*
796 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
797 *
798 * Copy a null terminated string from the user address space into
799 * the kernel address space.
800 * NOTE: maxlength must be < 64K
801 */
802ENTRY(copyinstr)
803	movl	_curpcb,a0		| current pcb
804	movl	#Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults
805	movl	sp@(4),a0		| a0 = fromaddr
806	movl	sp@(8),a1		| a1 = toaddr
807	moveq	#0,d0
808	movw	sp@(14),d0		| d0 = maxlength
809	jlt	Lcisflt1		| negative count, error
810	jeq	Lcisdone		| zero count, all done
811	subql	#1,d0			| set up for dbeq
812Lcisloop:
813	movsb	a0@+,d1			| grab a byte
814	nop
815	movb	d1,a1@+			| copy it
816	dbeq	d0,Lcisloop		| if !null and more, continue
817	jne	Lcisflt2		| ran out of room, error
818	moveq	#0,d0			| got a null, all done
819Lcisdone:
820	tstl	sp@(16)			| return length desired?
821	jeq	Lcisret			| no, just return
822	subl	sp@(4),a0		| determine how much was copied
823	movl	sp@(16),a1		| return location
824	movl	a0,a1@			| stash it
825Lcisret:
826	movl	_curpcb,a0		| current pcb
827	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
828	rts
829Lcisflt1:
830	moveq	#EFAULT,d0		| copy fault
831	jra	Lcisdone
832Lcisflt2:
833	moveq	#ENAMETOOLONG,d0	| ran out of space
834	jra	Lcisdone
835
836/*
837 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
838 *
839 * Copy a null terminated string from the kernel
840 * address space to the user address space.
841 * NOTE: maxlength must be < 64K
842 */
843ENTRY(copyoutstr)
844	movl	_curpcb,a0		| current pcb
845	movl	#Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults
846	movl	sp@(4),a0		| a0 = fromaddr
847	movl	sp@(8),a1		| a1 = toaddr
848	moveq	#0,d0
849	movw	sp@(14),d0		| d0 = maxlength
850	jlt	Lcosflt1		| negative count, error
851	jeq	Lcosdone		| zero count, all done
852	subql	#1,d0			| set up for dbeq
853Lcosloop:
854	movb	a0@+,d1			| grab a byte
855	movsb	d1,a1@+			| copy it
856	nop
857	dbeq	d0,Lcosloop		| if !null and more, continue
858	jne	Lcosflt2		| ran out of room, error
859	moveq	#0,d0			| got a null, all done
860Lcosdone:
861	tstl	sp@(16)			| return length desired?
862	jeq	Lcosret			| no, just return
863	subl	sp@(4),a0		| determine how much was copied
864	movl	sp@(16),a1		| return location
865	movl	a0,a1@			| stash it
866Lcosret:
867	movl	_curpcb,a0		| current pcb
868	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
869	rts
870Lcosflt1:
871	moveq	#EFAULT,d0		| copy fault
872	jra	Lcosdone
873Lcosflt2:
874	moveq	#ENAMETOOLONG,d0	| ran out of space
875	jra	Lcosdone
876
877/*
878 * copystr(fromaddr, toaddr, maxlength, &lencopied)
879 *
880 * Copy a null terminated string from one point to another in
881 * the kernel address space.
882 * NOTE: maxlength must be < 64K
883 */
884ENTRY(copystr)
885	movl	sp@(4),a0		| a0 = fromaddr
886	movl	sp@(8),a1		| a1 = toaddr
887	moveq	#0,d0
888	movw	sp@(14),d0		| d0 = maxlength
889	jlt	Lcsflt1			| negative count, error
890	jeq	Lcsdone			| zero count, all done
891	subql	#1,d0			| set up for dbeq
892Lcsloop:
893	movb	a0@+,a1@+		| copy a byte
894	dbeq	d0,Lcsloop		| if !null and more, continue
895	jne	Lcsflt2			| ran out of room, error
896	moveq	#0,d0			| got a null, all done
897Lcsdone:
898	tstl	sp@(16)			| return length desired?
899	jeq	Lcsret			| no, just return
900	subl	sp@(4),a0		| determine how much was copied
901	movl	sp@(16),a1		| return location
902	movl	a0,a1@			| stash it
903Lcsret:
904	rts
905Lcsflt1:
906	moveq	#EFAULT,d0		| copy fault
907	jra	Lcsdone
908Lcsflt2:
909	moveq	#ENAMETOOLONG,d0	| ran out of space
910	jra	Lcsdone
911
912/*
913 * Copyin(from, to, len)
914 *
915 * Copy specified amount of data from user space into the kernel.
916 * NOTE: len must be < 64K
917 */
918ENTRY(copyin)
919	movl	d2,sp@-			| scratch register
920	movl	_curpcb,a0		| current pcb
921	movl	#Lciflt,a0@(PCB_ONFAULT) | set up to catch faults
922	movl	sp@(16),d2		| check count
923	jlt	Lciflt			| negative, error
924	jeq	Lcidone			| zero, done
925	movl	sp@(8),a0		| src address
926	movl	sp@(12),a1		| dest address
927	movl	a0,d0
928	btst	#0,d0			| src address odd?
929	jeq	Lcieven			| no, go check dest
930	movsb	a0@+,d1			| yes, get a byte
931	nop
932	movb	d1,a1@+			| put a byte
933	subql	#1,d2			| adjust count
934	jeq	Lcidone			| exit if done
935Lcieven:
936	movl	a1,d0
937	btst	#0,d0			| dest address odd?
938	jne	Lcibyte			| yes, must copy by bytes
939	movl	d2,d0			| no, get count
940	lsrl	#2,d0			| convert to longwords
941	jeq	Lcibyte			| no longwords, copy bytes
942	subql	#1,d0			| set up for dbf
943Lcilloop:
944	movsl	a0@+,d1			| get a long
945	nop
946	movl	d1,a1@+			| put a long
947	dbf	d0,Lcilloop		| til done
948	andl	#3,d2			| what remains
949	jeq	Lcidone			| all done
950Lcibyte:
951	subql	#1,d2			| set up for dbf
952Lcibloop:
953	movsb	a0@+,d1			| get a byte
954	nop
955	movb	d1,a1@+			| put a byte
956	dbf	d2,Lcibloop		| til done
957Lcidone:
958	moveq	#0,d0			| success
959Lciexit:
960	movl	_curpcb,a0		| current pcb
961	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
962	movl	sp@+,d2			| restore scratch reg
963	rts
964Lciflt:
965	moveq	#EFAULT,d0		| got a fault
966	jra	Lciexit
967
968/*
969 * Copyout(from, to, len)
970 *
971 * Copy specified amount of data from kernel to the user space
972 * NOTE: len must be < 64K
973 */
974ENTRY(copyout)
975	movl	d2,sp@-			| scratch register
976	movl	_curpcb,a0		| current pcb
977	movl	#Lcoflt,a0@(PCB_ONFAULT) | catch faults
978	movl	sp@(16),d2		| check count
979	jlt	Lcoflt			| negative, error
980	jeq	Lcodone			| zero, done
981	movl	sp@(8),a0		| src address
982	movl	sp@(12),a1		| dest address
983	movl	a0,d0
984	btst	#0,d0			| src address odd?
985	jeq	Lcoeven			| no, go check dest
986	movb	a0@+,d1			| yes, get a byte
987	movsb	d1,a1@+			| put a byte
988	nop
989	subql	#1,d2			| adjust count
990	jeq	Lcodone			| exit if done
991Lcoeven:
992	movl	a1,d0
993	btst	#0,d0			| dest address odd?
994	jne	Lcobyte			| yes, must copy by bytes
995	movl	d2,d0			| no, get count
996	lsrl	#2,d0			| convert to longwords
997	jeq	Lcobyte			| no longwords, copy bytes
998	subql	#1,d0			| set up for dbf
999Lcolloop:
1000	movl	a0@+,d1			| get a long
1001	movsl	d1,a1@+			| put a long
1002	nop
1003	dbf	d0,Lcolloop		| til done
1004	andl	#3,d2			| what remains
1005	jeq	Lcodone			| all done
1006Lcobyte:
1007	subql	#1,d2			| set up for dbf
1008Lcobloop:
1009	movb	a0@+,d1			| get a byte
1010	movsb	d1,a1@+			| put a byte
1011	nop
1012	dbf	d2,Lcobloop		| til done
1013Lcodone:
1014	moveq	#0,d0			| success
1015Lcoexit:
1016	movl	_curpcb,a0		| current pcb
1017	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1018	movl	sp@+,d2			| restore scratch reg
1019	rts
1020Lcoflt:
1021	moveq	#EFAULT,d0		| got a fault
1022	jra	Lcoexit
1023
1024/*
1025 * non-local gotos
1026 */
1027ENTRY(setjmp)
1028	movl	sp@(4),a0	| savearea pointer
1029	moveml	#0xFCFC,a0@	| save d2-d7/a2-a7
1030	movl	sp@,a0@(48)	| and return address
1031	moveq	#0,d0		| return 0
1032	rts
1033
1034ENTRY(qsetjmp)
1035	movl	sp@(4),a0	| savearea pointer
1036	lea	a0@(40),a0	| skip regs we do not save
1037	movl	a6,a0@+		| save FP
1038	movl	sp,a0@+		| save SP
1039	movl	sp@,a0@		| and return address
1040	moveq	#0,d0		| return 0
1041	rts
1042
1043ENTRY(longjmp)
1044	movl	sp@(4),a0
1045	moveml	a0@+,#0xFCFC
1046	movl	a0@,sp@
1047	moveq	#1,d0
1048	rts
1049
1050/*
1051 * The following primitives manipulate the run queues.
1052 * _whichqs tells which of the 32 queues _qs
1053 * have processes in them.  Setrq puts processes into queues, Remrq
1054 * removes them from queues.  The running process is on no queue,
1055 * other processes are on a queue related to p->p_pri, divided by 4
1056 * actually to shrink the 0-127 range of priorities into the 32 available
1057 * queues.
1058 */
1059
1060	.globl	_whichqs,_qs,_cnt,_panic
1061	.globl	_curproc,_want_resched
1062
1063/*
1064 * Setrq(p)
1065 *
1066 * Call should be made at spl6(), and p->p_stat should be SRUN
1067 */
1068ENTRY(setrq)
1069	movl	sp@(4),a0
1070	tstl	a0@(P_RLINK)
1071	jeq	Lset1
1072	movl	#Lset2,sp@-
1073	jbsr	_panic
1074Lset1:
1075	clrl	d0
1076	movb	a0@(P_PRI),d0
1077	lsrb	#2,d0
1078	movl	_whichqs,d1
1079	bset	d0,d1
1080	movl	d1,_whichqs
1081	lslb	#3,d0
1082	addl	#_qs,d0
1083	movl	d0,a0@(P_LINK)
1084	movl	d0,a1
1085	movl	a1@(P_RLINK),a0@(P_RLINK)
1086	movl	a0,a1@(P_RLINK)
1087	movl	a0@(P_RLINK),a1
1088	movl	a0,a1@(P_LINK)
1089	rts
1090
1091Lset2:
1092	.asciz	"setrq"
1093	.even
1094
1095/*
1096 * Remrq(p)
1097 *
1098 * Call should be made at spl6().
1099 */
1100ENTRY(remrq)
1101	movl	sp@(4),a0
1102	clrl	d0
1103	movb	a0@(P_PRI),d0
1104	lsrb	#2,d0
1105	movl	_whichqs,d1
1106	bclr	d0,d1
1107	jne	Lrem1
1108	movl	#Lrem3,sp@-
1109	jbsr	_panic
1110Lrem1:
1111	movl	d1,_whichqs
1112	movl	a0@(P_LINK),a1
1113	movl	a0@(P_RLINK),a1@(P_RLINK)
1114	movl	a0@(P_RLINK),a1
1115	movl	a0@(P_LINK),a1@(P_LINK)
1116	movl	#_qs,a1
1117	movl	d0,d1
1118	lslb	#3,d1
1119	addl	d1,a1
1120	cmpl	a1@(P_LINK),a1
1121	jeq	Lrem2
1122	movl	_whichqs,d1
1123	bset	d0,d1
1124	movl	d1,_whichqs
1125Lrem2:
1126	clrl	a0@(P_RLINK)
1127	rts
1128
1129Lrem3:
1130	.asciz	"remrq"
1131Lsw0:
1132	.asciz	"swtch"
1133	.even
1134
1135	.globl	_curpcb
1136	.globl	_masterpaddr	| XXX compatibility (debuggers)
1137	.data
1138_masterpaddr:			| XXX compatibility (debuggers)
1139_curpcb:
1140	.long	0
1141pcbflag:
1142	.byte	0		| copy of pcb_flags low byte
1143	.align	2
1144	.comm	nullpcb,SIZEOF_PCB
1145	.text
1146
1147/*
1148 * At exit of a process, do a swtch for the last time.
1149 * The mapping of the pcb at p->p_addr has already been deleted,
1150 * and the memory for the pcb+stack has been freed.
1151 * The ipl is high enough to prevent the memory from being reallocated.
1152 */
1153ENTRY(swtch_exit)
1154	movl	#nullpcb,_curpcb	| save state into garbage pcb
1155	lea	tmpstk,sp		| goto a tmp stack
1156	jra	_cpu_swtch
1157
1158/*
1159 * When no processes are on the runq, Swtch branches to idle
1160 * to wait for something to come ready.
1161 */
1162	.globl	Idle
1163Lidle:
1164	stop	#PSL_LOWIPL
1165Idle:
1166idle:
1167	movw	#PSL_HIGHIPL,sr
1168	tstl	_whichqs
1169	jeq	Lidle
1170	movw	#PSL_LOWIPL,sr
1171	jra	Lsw1
1172
1173Lbadsw:
1174	movl	#Lsw0,sp@-
1175	jbsr	_panic
1176	/*NOTREACHED*/
1177
1178/*
1179 * cpu_swtch()
1180 *
1181 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
1182 * entire ATC.  The effort involved in selective flushing may not be
1183 * worth it, maybe we should just flush the whole thing?
1184 *
1185 * NOTE 2: With the new VM layout we now no longer know if an inactive
1186 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1187 * bit).  For now, we just always flush the full ATC.
1188 */
1189ENTRY(cpu_swtch)
1190	movl	_curpcb,a0		| current pcb
1191	movw	sr,a0@(PCB_PS)		| save sr before changing ipl
1192#ifdef notyet
1193	movl	_curproc,sp@-		| remember last proc running
1194#endif
1195	clrl	_curproc
1196	addql	#1,_cnt+V_SWTCH
1197
1198Lsw1:
1199	/*
1200	 * Find the highest-priority queue that isn't empty,
1201	 * then take the first proc from that queue.
1202	 */
1203	clrl	d0
1204	lea	_whichqs,a0
1205	movl	a0@,d1
1206Lswchk:
1207	btst	d0,d1
1208	jne	Lswfnd
1209	addqb	#1,d0
1210	cmpb	#32,d0
1211	jne	Lswchk
1212	jra	idle
1213Lswfnd:
1214	movw	#PSL_HIGHIPL,sr		| lock out interrupts
1215	movl	a0@,d1			| and check again...
1216	bclr	d0,d1
1217	jeq	Lsw1			| proc moved, rescan
1218	movl	d1,a0@			| update whichqs
1219	moveq	#1,d1			| double check for higher priority
1220	lsll	d0,d1			| process (which may have snuck in
1221	subql	#1,d1			| while we were finding this one)
1222	andl	a0@,d1
1223	jeq	Lswok			| no one got in, continue
1224	movl	a0@,d1
1225	bset	d0,d1			| otherwise put this one back
1226	movl	d1,a0@
1227	jra	Lsw1			| and rescan
1228Lswok:
1229	movl	d0,d1
1230	lslb	#3,d1			| convert queue number to index
1231	addl	#_qs,d1			| locate queue (q)
1232	movl	d1,a1
1233	cmpl	a1@(P_LINK),a1		| anyone on queue?
1234	jeq	Lbadsw			| no, panic
1235	movl	a1@(P_LINK),a0			| p = q->p_link
1236	movl	a0@(P_LINK),a1@(P_LINK)		| q->p_link = p->p_link
1237	movl	a0@(P_LINK),a1			| q = p->p_link
1238	movl	a0@(P_RLINK),a1@(P_RLINK)	| q->p_rlink = p->p_rlink
1239	cmpl	a0@(P_LINK),d1		| anyone left on queue?
1240	jeq	Lsw2			| no, skip
1241	movl	_whichqs,d1
1242	bset	d0,d1			| yes, reset bit
1243	movl	d1,_whichqs
1244Lsw2:
1245	movl	a0,_curproc
1246	clrl	_want_resched
1247#ifdef notyet
1248	movl	sp@+,a1
1249	cmpl	a0,a1			| switching to same proc?
1250	jeq	Lswdone			| yes, skip save and restore
1251#endif
1252	/*
1253	 * Save state of previous process in its pcb.
1254	 */
1255	movl	_curpcb,a1
1256	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1257	movl	usp,a2			| grab USP (a2 has been saved)
1258	movl	a2,a1@(PCB_USP)		| and save it
1259#ifdef FPCOPROC
1260	lea	a1@(PCB_FPCTX),a2	| pointer to FP save area
1261	fsave	a2@			| save FP state
1262	tstb	a2@			| null state frame?
1263	jeq	Lswnofpsave		| yes, all done
1264	fmovem	fp0-fp7,a2@(216)	| save FP general registers
1265	fmovem	fpcr/fpsr/fpi,a2@(312)	| save FP control registers
1266Lswnofpsave:
1267#endif
1268
1269#ifdef DIAGNOSTIC
1270	tstl	a0@(P_WCHAN)
1271	jne	Lbadsw
1272	cmpb	#SRUN,a0@(P_STAT)
1273	jne	Lbadsw
1274#endif
1275	clrl	a0@(P_RLINK)		| clear back link
1276	movl	a0@(P_ADDR),a1		| get p_addr
1277	movl	a1,_curpcb
1278	movb	a1@(PCB_FLAGS+1),pcbflag | copy of pcb_flags low byte
1279
1280	/* see if pmap_activate needs to be called; should remove this */
1281	movl	a0@(P_VMSPACE),a0	| vmspace = p->p_vmspace
1282#ifdef DIAGNOSTIC
1283	tstl	a0			| map == VM_MAP_NULL?
1284	jeq	Lbadsw			| panic
1285#endif
1286	lea	a0@(VM_PMAP),a0		| pmap = &vmspace.vm_pmap
1287	tstl	a0@(PM_STCHG)		| pmap->st_changed?
1288	jeq	Lswnochg		| no, skip
1289	pea	a1@			| push pcb (at p_addr)
1290	pea	a0@			| push pmap
1291	jbsr	_pmap_activate		| pmap_activate(pmap, pcb)
1292	addql	#8,sp
1293	movl	_curpcb,a1		| restore p_addr
1294Lswnochg:
1295
1296	movl	#PGSHIFT,d1
1297	movl	a1,d0
1298	lsrl	d1,d0			| convert p_addr to page number
1299	lsll	#2,d0			| and now to Sysmap offset
1300	addl	_Sysmap,d0		| add Sysmap base to get PTE addr
1301#ifdef notdef
1302	movw	#PSL_HIGHIPL,sr		| go crit while changing PTEs
1303#endif
1304	lea	tmpstk,sp		| now goto a tmp stack for NMI
1305	movl	d0,a0			| address of new context
1306	movl	_Umap,a2		| address of PTEs for kstack
1307	moveq	#UPAGES-1,d0		| sizeof kstack
1308Lres1:
1309	movl	a0@+,d1			| get PTE
1310	andl	#~PG_PROT,d1		| mask out old protection
1311	orl	#PG_RW+PG_V,d1		| ensure valid and writable
1312	movl	d1,a2@+			| load it up
1313	dbf	d0,Lres1		| til done
1314	movl	#CACHE_CLR,d0
1315	movc	d0,cacr			| invalidate cache(s)
1316	pflusha				| flush entire TLB
1317	movl	a1@(PCB_USTP),d0	| get USTP
1318	moveq	#PGSHIFT,d1
1319	lsll	d1,d0			| convert to addr
1320	lea	_protorp,a0		| CRP prototype
1321	movl	d0,a0@(4)		| stash USTP
1322	pmove	a0@,crp			| load new user root pointer
1323	moveml	a1@(PCB_REGS),#0xFCFC	| and registers
1324	movl	a1@(PCB_USP),a0
1325	movl	a0,usp			| and USP
1326#ifdef FPCOPROC
1327	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1328	tstb	a0@			| null state frame?
1329	jeq	Lresfprest		| yes, easy
1330	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
1331	fmovem	a0@(216),fp0-fp7	| restore FP general registers
1332Lresfprest:
1333	frestore a0@			| restore state
1334#endif
1335	movw	a1@(PCB_PS),sr		| no, restore PS
1336	moveq	#1,d0			| return 1 (for alternate returns)
1337	rts
1338
1339/*
1340 * savectx(pcb, altreturn)
1341 * Update pcb, saving current processor state and arranging
1342 * for alternate return ala longjmp in swtch if altreturn is true.
1343 */
1344ENTRY(savectx)
1345	movl	sp@(4),a1
1346	movw	sr,a1@(PCB_PS)
1347	movl	usp,a0			| grab USP
1348	movl	a0,a1@(PCB_USP)		| and save it
1349	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1350#ifdef FPCOPROC
1351	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1352	fsave	a0@			| save FP state
1353	tstb	a0@			| null state frame?
1354	jeq	Lsvnofpsave		| yes, all done
1355	fmovem	fp0-fp7,a0@(216)	| save FP general registers
1356	fmovem	fpcr/fpsr/fpi,a0@(312)	| save FP control registers
1357Lsvnofpsave:
1358#endif
1359	tstl	sp@(8)			| altreturn?
1360	jeq	Lsavedone
1361	movl	sp,d0			| relocate current sp relative to a1
1362	subl	#_kstack,d0		|   (sp is relative to kstack):
1363	addl	d0,a1			|   a1 += sp - kstack;
1364	movl	sp@,a1@			| write return pc at (relocated) sp@
1365Lsavedone:
1366	moveq	#0,d0			| return 0
1367	rts
1368
1369/*
1370 * {fu,su},{byte,sword,word}
1371 */
1372ALTENTRY(fuiword, _fuword)
1373ENTRY(fuword)
1374	movl	sp@(4),a0		| address to read
1375	movl	_curpcb,a1		| current pcb
1376	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1377	movsl	a0@,d0			| do read from user space
1378	nop
1379	jra	Lfsdone
1380
1381ENTRY(fusword)
1382	movl	sp@(4),a0
1383	movl	_curpcb,a1		| current pcb
1384	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1385	moveq	#0,d0
1386	movsw	a0@,d0			| do read from user space
1387	nop
1388	jra	Lfsdone
1389
1390/* Just like fusword, but tells trap code not to page in. */
1391ENTRY(fuswintr)
1392	movl	sp@(4),a0
1393	movl	_curpcb,a1
1394	movl	#_fswintr,a1@(PCB_ONFAULT)
1395	moveq	#0,d0
1396	movsw	a0@,d0
1397	nop
1398	jra	Lfsdone
1399
1400ALTENTRY(fuibyte, _fubyte)
1401ENTRY(fubyte)
1402	movl	sp@(4),a0		| address to read
1403	movl	_curpcb,a1		| current pcb
1404	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1405	moveq	#0,d0
1406	movsb	a0@,d0			| do read from user space
1407	nop
1408	jra	Lfsdone
1409
1410Lfserr:
1411	moveq	#-1,d0			| error indicator
1412Lfsdone:
1413	clrl	a1@(PCB_ONFAULT) 	| clear fault address
1414	rts
1415
1416/* Just like Lfserr, but the address is different (& exported). */
1417	.globl	_fswintr
1418_fswintr:
1419	moveq	#-1,d0
1420	jra	Lfsdone
1421
1422
1423/*
1424 * Write a longword in user instruction space.
1425 * Largely the same as suword but with a final i-cache purge on those
1426 * machines with split caches.
1427 */
1428ENTRY(suiword)
1429	movl	sp@(4),a0		| address to write
1430	movl	sp@(8),d0		| value to put there
1431	movl	_curpcb,a1		| current pcb
1432	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1433	movsl	d0,a0@			| do write to user space
1434	nop
1435	moveq	#0,d0			| indicate no fault
1436	movl	#IC_CLEAR,d1
1437	movc	d1,cacr			| invalidate i-cache
1438	jra	Lfsdone
1439
1440ENTRY(suword)
1441	movl	sp@(4),a0		| address to write
1442	movl	sp@(8),d0		| value to put there
1443	movl	_curpcb,a1		| current pcb
1444	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1445	movsl	d0,a0@			| do write to user space
1446	nop
1447	moveq	#0,d0			| indicate no fault
1448	jra	Lfsdone
1449
1450ENTRY(susword)
1451	movl	sp@(4),a0		| address to write
1452	movw	sp@(10),d0		| value to put there
1453	movl	_curpcb,a1		| current pcb
1454	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1455	movsw	d0,a0@			| do write to user space
1456	nop
1457	moveq	#0,d0			| indicate no fault
1458	jra	Lfsdone
1459
1460ENTRY(suswintr)
1461	movl	sp@(4),a0
1462	movw	sp@(10),d0
1463	movl	_curpcb,a1
1464	movl	#_fswintr,a1@(PCB_ONFAULT)
1465	movsw	d0,a0@
1466	nop
1467	moveq	#0,d0
1468	jra	Lfsdone
1469
1470ALTENTRY(suibyte, _subyte)
1471ENTRY(subyte)
1472	movl	sp@(4),a0		| address to write
1473	movb	sp@(11),d0		| value to put there
1474	movl	_curpcb,a1		| current pcb
1475	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1476	movsb	d0,a0@			| do write to user space
1477	nop
1478	moveq	#0,d0			| indicate no fault
1479	jra	Lfsdone
1480
1481/*
1482 * Invalidate entire TLB.
1483 */
1484ENTRY(TBIA)
1485__TBIA:
1486	pflusha				| flush entire TLB
1487	movl	#DC_CLEAR,d0
1488	movc	d0,cacr			| invalidate on-chip d-cache
1489	rts
1490
1491/*
1492 * Invalidate any TLB entry for given VA (TB Invalidate Single)
1493 */
1494ENTRY(TBIS)
1495#ifdef DEBUG
1496	tstl	fulltflush		| being conservative?
1497	jne	__TBIA			| yes, flush entire TLB
1498#endif
1499
1500	movl	sp@(4),a0		| get addr to flush
1501	pflush	#0,#0,a0@		| flush address from both sides
1502	movl	#DC_CLEAR,d0
1503	movc	d0,cacr			| invalidate on-chip data cache
1504	rts
1505
1506/*
1507 * Invalidate supervisor side of TLB
1508 */
1509ENTRY(TBIAS)
1510#ifdef DEBUG
1511	tstl	fulltflush		| being conservative?
1512	jne	__TBIA			| yes, flush everything
1513#endif
1514	pflush #4,#4			| flush supervisor TLB entries
1515	movl	#DC_CLEAR,d0
1516	movc	d0,cacr			| invalidate on-chip d-cache
1517	rts
1518
1519/*
1520 * Invalidate user side of TLB
1521 */
1522ENTRY(TBIAU)
1523#ifdef DEBUG
1524	tstl	fulltflush		| being conservative?
1525	jne	__TBIA			| yes, flush everything
1526#endif
1527	pflush	#0,#4			| flush user TLB entries
1528	movl	#DC_CLEAR,d0
1529	movc	d0,cacr			| invalidate on-chip d-cache
1530	rts
1531
1532/*
1533 * Invalidate instruction cache
1534 */
1535ENTRY(ICIA)
1536	movl	#IC_CLEAR,d0
1537	movc	d0,cacr			| invalidate i-cache
1538	rts
1539
1540ENTRY(PCIA)
1541	movl	#DC_CLEAR,d0
1542	movc	d0,cacr			| invalidate on-chip d-cache
1543	rts
1544
1545/*
1546 * Get callers current SP value.
1547 * Note that simply taking the address of a local variable in a C function
1548 * doesn't work because callee saved registers may be outside the stack frame
1549 * defined by A6 (e.g. GCC generated code).
1550 */
1551	.globl	_getsp
1552_getsp:
1553	movl	sp,d0			| get current SP
1554	addql	#4,d0			| compensate for return address
1555	rts
1556
1557	.globl	_getsfc, _getdfc
1558_getsfc:
1559	movc	sfc,d0
1560	rts
1561_getdfc:
1562	movc	dfc,d0
1563	rts
1564
1565/*
1566 * Load a new user segment table pointer.
1567 */
1568ENTRY(loadustp)
1569	movl	sp@(4),d0		| new USTP
1570	moveq	#PGSHIFT,d1
1571	lsll	d1,d0			| convert to addr
1572	lea	_protorp,a0		| CRP prototype
1573	movl	d0,a0@(4)		| stash USTP
1574	pmove	a0@,crp			| load root pointer
1575	movl	#DC_CLEAR,d0
1576	movc	d0,cacr			| invalidate on-chip d-cache
1577	rts
1578
1579ENTRY(ploadw)
1580	movl	sp@(4),a0		| address to load
1581	ploadw	#1,a0@			| pre-load translation
1582	rts
1583
1584/*
1585 * Set processor priority level calls.  Most are implemented with
1586 * inline asm expansions.  However, spl0 requires special handling
1587 * as we need to check for our emulated software interrupts.
1588 */
1589
1590ENTRY(spl0)
1591	moveq	#0,d0
1592	movw	sr,d0			| get old SR for return
1593	movw	#PSL_LOWIPL,sr		| restore new SR
1594	tstb	_ssir			| software interrupt pending?
1595	jeq	Lspldone		| no, all done
1596	subql	#4,sp			| make room for RTE frame
1597	movl	sp@(4),sp@(2)		| position return address
1598	clrw	sp@(6)			| set frame type 0
1599	movw	#PSL_LOWIPL,sp@		| and new SR
1600	jra	Lgotsir			| go handle it
1601Lspldone:
1602	rts
1603
1604ENTRY(_insque)
1605	movw	sr,d0
1606	movw	#PSL_HIGHIPL,sr		| atomic
1607	movl	sp@(8),a0		| where to insert (after)
1608	movl	sp@(4),a1		| element to insert (e)
1609	movl	a0@,a1@			| e->next = after->next
1610	movl	a0,a1@(4)		| e->prev = after
1611	movl	a1,a0@			| after->next = e
1612	movl	a1@,a0
1613	movl	a1,a0@(4)		| e->next->prev = e
1614	movw	d0,sr
1615	rts
1616
1617ENTRY(_remque)
1618	movw	sr,d0
1619	movw	#PSL_HIGHIPL,sr		| atomic
1620	movl	sp@(4),a0		| element to remove (e)
1621	movl	a0@,a1
1622	movl	a0@(4),a0
1623	movl	a0,a1@(4)		| e->next->prev = e->prev
1624	movl	a1,a0@			| e->prev->next = e->next
1625	movw	d0,sr
1626	rts
1627
1628/*
1629 * bzero(addr, count)
1630 */
1631ALTENTRY(blkclr, _bzero)
1632ENTRY(bzero)
1633	movl	sp@(4),a0	| address
1634	movl	sp@(8),d0	| count
1635	jeq	Lbzdone		| if zero, nothing to do
1636	movl	a0,d1
1637	btst	#0,d1		| address odd?
1638	jeq	Lbzeven		| no, can copy words
1639	clrb	a0@+		| yes, zero byte to get to even boundary
1640	subql	#1,d0		| decrement count
1641	jeq	Lbzdone		| none left, all done
1642Lbzeven:
1643	movl	d0,d1
1644	andl	#31,d0
1645	lsrl	#5,d1		| convert count to 8*longword count
1646	jeq	Lbzbyte		| no such blocks, zero byte at a time
1647Lbzloop:
1648	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
1649	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
1650	subql	#1,d1		| one more block zeroed
1651	jne	Lbzloop		| more to go, do it
1652	tstl	d0		| partial block left?
1653	jeq	Lbzdone		| no, all done
1654Lbzbyte:
1655	clrb	a0@+
1656	subql	#1,d0		| one more byte cleared
1657	jne	Lbzbyte		| more to go, do it
1658Lbzdone:
1659	rts
1660
1661/*
1662 * strlen(str)
1663 */
1664ENTRY(strlen)
1665	moveq	#-1,d0
1666	movl	sp@(4),a0	| string
1667Lslloop:
1668	addql	#1,d0		| increment count
1669	tstb	a0@+		| null?
1670	jne	Lslloop		| no, keep going
1671	rts
1672
1673/*
1674 * bcmp(s1, s2, len)
1675 *
1676 * WARNING!  This guy only works with counts up to 64K
1677 */
1678ENTRY(bcmp)
1679	movl	sp@(4),a0		| string 1
1680	movl	sp@(8),a1		| string 2
1681	moveq	#0,d0
1682	movw	sp@(14),d0		| length
1683	jeq	Lcmpdone		| if zero, nothing to do
1684	subqw	#1,d0			| set up for DBcc loop
1685Lcmploop:
1686	cmpmb	a0@+,a1@+		| equal?
1687	dbne	d0,Lcmploop		| yes, keep going
1688	addqw	#1,d0			| +1 gives zero on match
1689Lcmpdone:
1690	rts
1691
1692/*
1693 * {ov}bcopy(from, to, len)
1694 *
1695 * Works for counts up to 128K.
1696 */
1697ALTENTRY(ovbcopy, _bcopy)
1698ENTRY(bcopy)
1699	movl	sp@(12),d0		| get count
1700	jeq	Lcpyexit		| if zero, return
1701	movl	sp@(4),a0		| src address
1702	movl	sp@(8),a1		| dest address
1703	cmpl	a1,a0			| src before dest?
1704	jlt	Lcpyback		| yes, copy backwards (avoids overlap)
1705	movl	a0,d1
1706	btst	#0,d1			| src address odd?
1707	jeq	Lcfeven			| no, go check dest
1708	movb	a0@+,a1@+		| yes, copy a byte
1709	subql	#1,d0			| update count
1710	jeq	Lcpyexit		| exit if done
1711Lcfeven:
1712	movl	a1,d1
1713	btst	#0,d1			| dest address odd?
1714	jne	Lcfbyte			| yes, must copy by bytes
1715	movl	d0,d1			| no, get count
1716	lsrl	#2,d1			| convert to longwords
1717	jeq	Lcfbyte			| no longwords, copy bytes
1718	subql	#1,d1			| set up for dbf
1719Lcflloop:
1720	movl	a0@+,a1@+		| copy longwords
1721	dbf	d1,Lcflloop		| til done
1722	andl	#3,d0			| get remaining count
1723	jeq	Lcpyexit		| done if none
1724Lcfbyte:
1725	subql	#1,d0			| set up for dbf
1726Lcfbloop:
1727	movb	a0@+,a1@+		| copy bytes
1728	dbf	d0,Lcfbloop		| til done
1729Lcpyexit:
1730	rts
1731Lcpyback:
1732	addl	d0,a0			| add count to src
1733	addl	d0,a1			| add count to dest
1734	movl	a0,d1
1735	btst	#0,d1			| src address odd?
1736	jeq	Lcbeven			| no, go check dest
1737	movb	a0@-,a1@-		| yes, copy a byte
1738	subql	#1,d0			| update count
1739	jeq	Lcpyexit		| exit if done
1740Lcbeven:
1741	movl	a1,d1
1742	btst	#0,d1			| dest address odd?
1743	jne	Lcbbyte			| yes, must copy by bytes
1744	movl	d0,d1			| no, get count
1745	lsrl	#2,d1			| convert to longwords
1746	jeq	Lcbbyte			| no longwords, copy bytes
1747	subql	#1,d1			| set up for dbf
1748Lcblloop:
1749	movl	a0@-,a1@-		| copy longwords
1750	dbf	d1,Lcblloop		| til done
1751	andl	#3,d0			| get remaining count
1752	jeq	Lcpyexit		| done if none
1753Lcbbyte:
1754	subql	#1,d0			| set up for dbf
1755Lcbbloop:
1756	movb	a0@-,a1@-		| copy bytes
1757	dbf	d0,Lcbbloop		| til done
1758	rts
1759
1760/*
1761 * Emulate fancy VAX string operations:
1762 *	scanc(count, startc, table, mask)
1763 *	skpc(mask, count, startc)
1764 *	locc(mask, count, startc)
1765 */
1766ENTRY(scanc)
1767	movl	sp@(4),d0	| get length
1768	jeq	Lscdone		| nothing to do, return
1769	movl	sp@(8),a0	| start of scan
1770	movl	sp@(12),a1	| table to compare with
1771	movb	sp@(19),d1	| and mask to use
1772	movw	d2,sp@-		| need a scratch register
1773	clrw	d2		| clear it out
1774	subqw	#1,d0		| adjust for dbra
1775Lscloop:
1776	movb	a0@+,d2		| get character
1777	movb	a1@(0,d2:w),d2	| get table entry
1778	andb	d1,d2		| mask it
1779	dbne	d0,Lscloop	| keep going til no more or non-zero
1780	addqw	#1,d0		| overshot by one
1781	movw	sp@+,d2		| restore scratch
1782Lscdone:
1783	rts
1784
1785ENTRY(skpc)
1786	movl	sp@(8),d0	| get length
1787	jeq	Lskdone		| nothing to do, return
1788	movb	sp@(7),d1	| mask to use
1789	movl	sp@(12),a0	| where to start
1790	subqw	#1,d0		| adjust for dbcc
1791Lskloop:
1792	cmpb	a0@+,d1		| compate with mask
1793	dbne	d0,Lskloop	| keep going til no more or zero
1794	addqw	#1,d0		| overshot by one
1795Lskdone:
1796	rts
1797
1798ENTRY(locc)
1799	movl	sp@(8),d0	| get length
1800	jeq	Llcdone		| nothing to do, return
1801	movb	sp@(7),d1	| mask to use
1802	movl	sp@(12),a0	| where to start
1803	subqw	#1,d0		| adjust for dbcc
1804Llcloop:
1805	cmpb	a0@+,d1		| compate with mask
1806	dbeq	d0,Llcloop	| keep going til no more or non-zero
1807	addqw	#1,d0		| overshot by one
1808Llcdone:
1809	rts
1810
1811/*
1812 * Emulate VAX FFS (find first set) instruction.
1813 */
1814ENTRY(ffs)
1815	moveq	#-1,d0
1816	movl	sp@(4),d1
1817	jeq	Lffsdone
1818Lffsloop:
1819	addql	#1,d0
1820	btst	d0,d1
1821	jeq	Lffsloop
1822Lffsdone:
1823	addql	#1,d0
1824	rts
1825
1826#ifdef FPCOPROC
1827/*
1828 * Save and restore 68881 state.
1829 * Pretty awful looking since our assembler does not
1830 * recognize FP mnemonics.
1831 */
1832ENTRY(m68881_save)
1833	movl	sp@(4),a0		| save area pointer
1834	fsave	a0@			| save state
1835	tstb	a0@			| null state frame?
1836	jeq	Lm68881sdone		| yes, all done
1837	fmovem fp0-fp7,a0@(216)		| save FP general registers
1838	fmovem fpcr/fpsr/fpi,a0@(312)	| save FP control registers
1839Lm68881sdone:
1840	rts
1841
1842ENTRY(m68881_restore)
1843	movl	sp@(4),a0		| save area pointer
1844	tstb	a0@			| null state frame?
1845	jeq	Lm68881rdone		| yes, easy
1846	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
1847	fmovem	a0@(216),fp0-fp7	| restore FP general registers
1848Lm68881rdone:
1849	frestore a0@			| restore state
1850	rts
1851
1852/* LUNA */
1853
1854	.globl	_fpp_svarea
1855
1856/* Fpp is MC68882 ? */
1857ENTRY(is_68882)
1858	frestore _fppnull	| initialize fpp
1859	movl	#2,d0
1860	fmovecr	#0,fp1
1861	fsinx	fp1,fp2
1862	lea	_fpp_svarea,a0	| save area
1863	movw	sr,d1		| save status reg.
1864	movw	#0x2700,sr	| mask intrrupt
1865	fsave	a0@		| save fpp context
1866	movw	d1,sr		| restore status reg.
1867	movl	a0@,d1
1868	andl	#0x00ff0000,d1  | check status field
1869	cmpl	#0x00180000,d1  | 68881(idle)?
1870	beq	_is81
1871	cmpl	#0x00b40000,d1	| 68881(busy)?
1872	beq	_is81
1873	cmpl	#0x00380000,d1	| 68882(idle)?
1874	beq	_is82
1875	cmpl	#0x00d40000,d1	| 68882(busy)?
1876	beq	_is82
1877	bra	_is82out	| default 68881
1878_is81:
1879	clrl	d0
1880	bra	_is82out
1881_is82:
1882	movl	#1,d0
1883_is82out:
1884	frestore a0@
1885	rts
1886
1887#ifdef	OLD_LUNA
1888/* We have fpp ? */
1889ENTRY(havefpp)
1890	movl	a2,sp@-
1891	clrl	d0
1892	movl	vb,a2
1893	movl	a2@(FLINE_VEC),a0	| save vectors
1894	movl	a2@(COPRO_VEC),a1
1895	movl	sp,d1
1896	movl	#_fpvec,a2@(FLINE_VEC)	| change vectors
1897	movl	#_fpvec,a2@(COPRO_VEC)
1898	fnop				| cause exception ?
1899	movl	#1,d0
1900_fpvec:	movl	a0,a2@(FLINE_VEC)	| restore vectors
1901	movl	a1,a2@(COPRO_VEC)
1902	movl	d1,sp
1903	movl	sp@+,a2
1904	rts
1905#endif
1906#endif
1907
1908/*
1909 * Handle the nitty-gritty of rebooting the machine.
1910 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
1911 * Note that we must be running in an address range that is mapped one-to-one
1912 * logical to physical so that the PC is still valid immediately after the MMU
1913 * is turned off.  We have conveniently mapped the last page of physical
1914 * memory this way.
1915 */
1916	.globl	_doboot
1917_doboot:
1918	movl	#0x41000004,a0
1919	movl	a0@,a1			| get PROM restart entry address
1920	movl	#CACHE_OFF,d0
1921	movc	d0,cacr			| disable on-chip cache(s)
1922	movl	#_tcroff,a0		| value for pmove to TC (turn off MMU)
1923	pmove	a0@,tc			| disable MMU
1924	jmp	a1@			| goto REBOOT
1925
1926	.data
1927	.space	NBPG
1928tmpstk:
1929	.globl	_protorp,_protott0,_protott1
1930_protorp:
1931	.long	0,0		| prototype root pointer
1932_protott0:
1933	.long	0x807F8543	| prototype tt0 register (for kernel)
1934_protott1:
1935	.long	0		| prototype tt0 register (for user)
1936	.globl	_cold
1937_cold:
1938	.long	1		| cold start flag
1939	.globl	_want_resched
1940_want_resched:
1941	.long	0
1942	.globl	_proc0paddr
1943_proc0paddr:
1944	.long	0		| KVA of proc0 u-area
1945
1946	.globl	_tcroff
1947_tcroff:
1948	.long	0		| TC reg. reset flag
1949
1950#ifdef FPCOPROC
1951	.globl	_fppnull
1952_fppnull:
1953	.long	0
1954#endif
1955	.globl	_clock_on
1956_clock_on:
1957	.long	0		| clock is enable ?
1958	.globl	_dipswitch
1959_dipswitch:
1960	.word	0		| dipsw(front panel) value
1961#ifdef DEBUG
1962	.globl	fulltflush, fullcflush
1963fulltflush:
1964	.long	0
1965fullcflush:
1966	.long	0
1967	.globl	timebomb
1968timebomb:
1969	.long	0
1970#endif
1971/* interrupt counters */
1972	.globl	_intrcnt,_eintrcnt,_intrnames,_eintrnames
1973_intrnames:
1974	.asciz	"spur"
1975	.asciz	"lev1"
1976	.asciz	"lev2"
1977	.asciz	"lev3"
1978	.asciz	"lev4"
1979	.asciz	"clock"
1980	.asciz	"lev7"
1981	.asciz	"nmi"
1982_eintrnames:
1983	.even
1984_intrcnt:
1985	.long	0,0,0,0,0,0,0,0,0
1986_eintrcnt:
1987