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