xref: /netbsd/sys/arch/amiga/amiga/locore.s (revision c4a72b64)
1/*	$NetBSD: locore.s,v 1.132 2002/11/02 20:03:04 chs Exp $	*/
2
3/*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1980, 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the University of
23 *	California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: Utah $Hdr: locore.s 1.58 91/04/22$
41 *
42 *	@(#)locore.s	7.11 (Berkeley) 5/9/91
43 *
44 * Original (hp300) Author: unknown, maybe Mike Hibler?
45 * Amiga author: Markus Wild
46 * Other contributors: Bryan Ford (kernel reload stuff)
47 */
48
49#include "opt_bb060stupidrom.h"
50#include "opt_p5ppc68kboard.h"
51#include "opt_compat_netbsd.h"
52#include "opt_compat_svr4.h"
53#include "opt_compat_sunos.h"
54#include "opt_fpsp.h"
55#include "opt_kgdb.h"
56#include "opt_lockdebug.h"
57
58#include "opt_lev6_defer.h"
59
60#include "assym.h"
61#include <machine/asm.h>
62#include <machine/trap.h>
63
64	.text
65GLOBAL(kernel_text)
66L_base:
67	.long	0x4ef80400+NBPG	/* jmp jmp0.w */
68	.fill	NBPG/4-1,4,0/*xdeadbeef*/
69
70#include <amiga/amiga/vectors.s>
71#include <amiga/amiga/custom.h>
72
73#ifdef DRACO
74#include <amiga/amiga/drcustom.h>
75#endif
76
77#define CIAAADDR(ar)	movl	_C_LABEL(CIAAbase),ar
78#define CIABADDR(ar)	movl	_C_LABEL(CIABbase),ar
79#define CUSTOMADDR(ar)	movl	_C_LABEL(CUSTOMbase),ar
80#define INTREQRADDR(ar)	movl	_C_LABEL(INTREQRaddr),ar
81#define INTREQWADDR(ar)	movl	_C_LABEL(INTREQWaddr),ar
82#define INTENAWADDR(ar) movl	_C_LABEL(amiga_intena_write),ar
83#define	INTENARADDR(ar)	movl	_C_LABEL(amiga_intena_read),ar
84
85	.text
86/*
87 * This is where we wind up if the kernel jumps to location 0.
88 * (i.e. a bogus PC)  This is known to immediately follow the vector
89 * table and is hence at 0x400 (see reset vector in vectors.s).
90 */
91	pea	Ljmp0panic
92	jbsr	_C_LABEL(panic)
93	/* NOTREACHED */
94Ljmp0panic:
95	.asciz	"kernel jump to zero"
96	.even
97
98/*
99 * Do a dump.
100 * Called by auto-restart.
101 */
102ENTRY_NOPROFILE(doadump)
103	jbsr	_C_LABEL(dumpsys)
104	jbsr	_C_LABEL(doboot)
105	/*NOTREACHED*/
106
107/*
108 * Trap/interrupt vector routines
109 */
110#include <m68k/m68k/trap_subr.s>
111
112#if defined(M68040) || defined(M68060)
113ENTRY_NOPROFILE(addrerr4060)
114	clrl	%sp@-			| stack adjust count
115	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
116	movl	%usp,%a0		| save the user SP
117	movl	%a0,%sp@(FR_SP)		|   in the savearea
118	movl	%sp@(FR_HW+8),%sp@-
119	clrl	%sp@-			| dummy code
120	movl	#T_ADDRERR,%sp@-	| mark address error
121	jra	_ASM_LABEL(faultstkadj)	| and deal with it
122#endif
123
124#if defined(M68060)
125ENTRY_NOPROFILE(buserr60)
126	clrl	%sp@-			| stack adjust count
127	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
128	movl	%usp,%a0		| save the user SP
129	movl	%a0,%sp@(FR_SP)		|   in the savearea
130	movel	%sp@(FR_HW+12),%d0	| FSLW
131	btst	#2,%d0			| branch prediction error?
132	jeq	Lnobpe
133	movc	%cacr,%d2
134	orl	#IC60_CABC,%d2		| clear all branch cache entries
135	movc	%d2,%cacr
136	movl	%d0,%d1
137	addql	#1,L60bpe
138	andl	#0x7ffd,%d1
139	jeq	_ASM_LABEL(faultstkadjnotrap2)
140Lnobpe:
141| we need to adjust for misaligned addresses
142	movl	%sp@(FR_HW+8),%d1	| grab VA
143	btst	#27,%d0			| check for mis-aligned access
144	jeq	Lberr3			| no, skip
145	addl	#28,%d1			| yes, get into next page
146					| operand case: 3,
147					| instruction case: 4+12+12
148	andl	#PG_FRAME,%d1           | and truncate
149Lberr3:
150	movl	%d1,%sp@-
151	movl	%d0,%sp@-		| code is FSLW now.
152	andw	#0x1f80,%d0
153	jeq	Lisberr
154	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
155	jra	_ASM_LABEL(faultstkadj)	| and deal with it
156#endif
157#if defined(M68040)
158ENTRY_NOPROFILE(buserr40)
159	clrl	%sp@-			| stack adjust count
160	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
161	movl	%usp,%a0		| save the user SP
162	movl	%a0,%sp@(FR_SP)		|   in the savearea
163	movl	%sp@(FR_HW+20),%d1	| get fault address
164	moveq	#0,%d0
165	movw	%sp@(FR_HW+12),%d0	| get SSW
166	btst	#11,%d0			| check for mis-aligned
167	jeq	Lbe1stpg		| no skip
168	addl	#3,%d1			| get into next page
169	andl	#PG_FRAME,%d1		| and truncate
170Lbe1stpg:
171	movl	%d1,%sp@-		| pass fault address.
172	movl	%d0,%sp@-		| pass SSW as code
173	btst	#10,%d0			| test ATC
174	jeq	Lisberr			| it is a bus error
175	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
176	jra	_ASM_LABEL(faultstkadj)	| and deal with it
177#endif
178
179ENTRY_NOPROFILE(buserr)
180ENTRY_NOPROFILE(addrerr)
181#if !(defined(M68020) || defined(M68030))
182	jra	_C_LABEL(badtrap)
183#else
184	clrl	%sp@-			| stack adjust count
185	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
186	movl	%usp,%a0		| save the user SP
187	movl	%a0,%sp@(FR_SP)		|   in the savearea
188	moveq	#0,%d0
189	movw	%sp@(FR_HW+10),%d0	| grab SSW for fault processing
190	btst	#12,%d0			| RB set?
191	jeq	LbeX0			| no, test RC
192	bset	#14,%d0			| yes, must set FB
193	movw	%d0,%sp@(FR_HW+10)	| for hardware too
194LbeX0:
195	btst	#13,%d0			| RC set?
196	jeq	LbeX1			| no, skip
197	bset	#15,%d0			| yes, must set FC
198	movw	%d0,%sp@(FR_HW+10)	| for hardware too
199LbeX1:
200	btst	#8,%d0			| data fault?
201	jeq	Lbe0			| no, check for hard cases
202	movl	%sp@(FR_HW+16),%d1	| fault address is as given in frame
203	jra	Lbe10			| thats it
204Lbe0:
205	btst	#4,%sp@(FR_HW+6)	| long (type B) stack frame?
206	jne	Lbe4			| yes, go handle
207	movl	%sp@(FR_HW+2),%d1	| no, can use save PC
208	btst	#14,%d0			| FB set?
209	jeq	Lbe3			| no, try FC
210	addql	#4,%d1			| yes, adjust address
211	jra	Lbe10			| done
212Lbe3:
213	btst	#15,%d0			| FC set?
214	jeq	Lbe10			| no, done
215	addql	#2,%d1			| yes, adjust address
216	jra	Lbe10			| done
217Lbe4:
218	movl	%sp@(FR_HW+36),%d1	| long format, use stage B address
219	btst	#15,%d0			| FC set?
220	jeq	Lbe10			| no, all done
221	subql	#2,%d1			| yes, adjust address
222Lbe10:
223	movl	%d1,%sp@-		| push fault VA
224	movl	%d0,%sp@-		| and padded SSW
225	movw	%sp@(FR_HW+8+6),%d0	| get frame format/vector offset
226	andw	#0x0FFF,%d0		| clear out frame format
227	cmpw	#12,%d0			| address error vector?
228	jeq	Lisaerr			| yes, go to it
229	movl	%d1,%a0			| fault address
230	movl	%sp@,%d0		| function code from ssw
231	btst	#8,%d0			| data fault?
232	jne	Lbe10a
233	movql	#1,%d0			| user program access FC
234					| (we dont separate data/program)
235	btst	#5,%sp@(FR_HW+8)	| supervisor mode?
236	jeq	Lbe10a			| if no, done
237	movql	#5,%d0			| else supervisor program access
238Lbe10a:
239	ptestr	%d0,%a0@,#7		| do a table search
240	pmove	%psr,%sp@		| save result
241	movb	%sp@,%d1
242	btst	#2,%d1			| invalid (incl. limit viol. and berr)?
243	jeq	Lmightnotbemerr		| no -> wp check
244	btst	#7,%d1			| is it MMU table berr?
245	jeq	Lismerr			| no, must be fast
246	jra	Lisberr1		| real bus err needs not be fast.
247Lmightnotbemerr:
248	btst	#3,%d1			| write protect bit set?
249	jeq	Lisberr1		| no: must be bus error
250	movl	%sp@,%d0		| ssw into low word of d0
251	andw	#0xc0,%d0		| Write protect is set on page:
252	cmpw	#0x40,%d0		| was it read cycle?
253	jeq	Lisberr1		| yes, was not WPE, must be bus err
254Lismerr:
255	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
256	jra	_ASM_LABEL(faultstkadj)	| and deal with it
257Lisaerr:
258	movl	#T_ADDRERR,%sp@-	| mark address error
259	jra	_ASM_LABEL(faultstkadj)	| and deal with it
260Lisberr1:
261	clrw	%sp@			| re-clear pad word
262#endif
263Lisberr:				| also used by M68040/60
264	tstl	_C_LABEL(nofault)	| device probe?
265	jeq	LberrIsProbe		| no, handle as usual
266	movl	_C_LABEL(nofault),%sp@-	| yes,
267	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
268	/* NOTREACHED */
269LberrIsProbe:
270	movl	#T_BUSERR,%sp@-		| mark bus error
271	jra	_ASM_LABEL(faultstkadj)	| and deal with it
272
273/*
274 * FP exceptions.
275 */
276ENTRY_NOPROFILE(fpfline)
277#if defined(M68040)
278	cmpw	#0x202c,%sp@(6)		| format type 2?
279	jne	_C_LABEL(illinst)	| no, not an FP emulation
280#ifdef FPSP
281	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
282#endif
283#endif
284
285#ifdef FPU_EMULATE
286ENTRY_NOPROFILE(fpemuli)
287	addql	#1,Lfpecnt
288	clrl	%sp@-			| stack adjust count
289	moveml	%d0-%d7/%a0-%a7,%sp@-	| save registers
290	movql	#T_FPEMULI,%d0		| denote as FP emulation trap
291	jra	_ASM_LABEL(fault)	| do it
292#endif
293
294ENTRY_NOPROFILE(fpunsupp)
295#if defined(M68040)
296	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
297	jne	_C_LABEL(illinst)	| no, treat as illinst
298#ifdef FPSP
299	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
300#else
301	clrl	%sp@-			| stack adjust count
302	moveml	%d0-%d7/%a0-%a7,%sp@-	| save registers
303	movql	#T_FPEMULD,%d0		| denote as FP emulation trap
304	jra	_ASM_LABEL(fault)	| do it
305#endif
306#else
307	jra	_C_LABEL(illinst)
308#endif
309/*
310 * Handles all other FP coprocessor exceptions.
311 * Note that since some FP exceptions generate mid-instruction frames
312 * and may cause signal delivery, we need to test for stack adjustment
313 * after the trap call.
314 */
315ENTRY_NOPROFILE(fpfault)
316#ifdef FPCOPROC
317	clrl	%sp@-			| stack adjust count
318	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
319	movl	%usp,%a0		| and save
320	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
321	clrl	%sp@-			| no VA arg
322	movl	_C_LABEL(curpcb),%a0	| current pcb
323	lea	%a0@(PCB_FPCTX),%a0	| address of FP savearea
324	fsave	%a0@			| save state
325#if defined(M68020) || defined(M68030)
326#if defined(M68060) || defined(M68040)
327	movb	_C_LABEL(machineid)+3,%d0
328	andb	#0x90,%d0		| AMIGA_68060 | AMIGA_68040
329	jne	Lfptnull		| XXX
330#endif
331	tstb	%a0@			| null state frame?
332	jeq	Lfptnull		| yes, safe
333	clrw	%d0			| no, need to tweak BIU
334	movb	%a0@(1),%d0		| get frame size
335	bset	#3,%a0@(0,%d0:w)	| set exc_pend bit of BIU
336Lfptnull:
337#endif
338	fmovem	%fpsr,%sp@-		| push fpsr as code argument
339	frestore %a0@			| restore state
340	movl	#T_FPERR,%sp@-		| push type arg
341	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
342#else
343	jra	_C_LABEL(badtrap)	| treat as an unexpected trap
344#endif
345
346/*
347 * Other exceptions only cause four and six word stack frame and require
348 * no post-trap stack adjustment.
349 */
350
351ENTRY_NOPROFILE(badtrap)
352	moveml	%d0/%d1/%a0/%a1,%sp@-	| save scratch regs
353	movw	%sp@(22),%sp@-		| push exception vector info
354	clrw	%sp@-
355	movl	%sp@(22),%sp@-		| and PC
356	jbsr	_C_LABEL(straytrap)	| report
357	addql	#8,%sp			| pop args
358	moveml	%sp@+,%d0/%d1/%a0/%a1	| restore regs
359	jra	_ASM_LABEL(rei)		| all done
360
361ENTRY_NOPROFILE(trap0)
362	clrl	%sp@-			| stack adjust count
363	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
364	movl	%usp,%a0		| save the user SP
365	movl	%a0,%sp@(FR_SP)		|   in the savearea
366	movl	%d0,%sp@-		| push syscall number
367	jbsr	_C_LABEL(syscall)	| handle it
368	addql	#4,%sp			| pop syscall arg
369	movl	%sp@(FR_SP),%a0		| grab and restore
370	movl	%a0,%usp		|   user SP
371	moveml	%sp@+,%d0-%d7/%a0-%a6	| restore most registers
372	addql	#8,%sp			| pop SP and stack adjust
373	jra	_ASM_LABEL(rei)		| all done
374
375/*
376 * Trap 12 is the entry point for the cachectl "syscall"
377 *	cachectl(command, addr, length)
378 * command in d0, addr in a1, length in d1
379 */
380ENTRY_NOPROFILE(trap12)
381	movl	_C_LABEL(curproc),%sp@-	| push current proc pointer
382	movl	%d1,%sp@-		| push length
383	movl	%a1,%sp@-		| push addr
384	movl	%d0,%sp@-		| push command
385	jbsr	_C_LABEL(cachectl1)	| do it
386	lea	%sp@(16),%sp		| pop args
387	jra	_ASM_LABEL(rei)		| all done
388
389/*
390 * Trap 15 is used for:
391 *	- KGDB traps
392 *	- trace traps for SUN binaries (not fully supported yet)
393 * We just pass it on and let trap() sort it all out
394 */
395ENTRY_NOPROFILE(trap15)
396	clrl	%sp@-
397	moveml	%d0-%d7/%a0-%a7,%sp@-
398#ifdef KGDB
399	moveq	#T_TRAP15,%d0
400	movw	%sp@(FR_HW),%d1		| get PSW
401	andw	#PSL_S,%d1		| from user mode?
402	jeq	_ASM_LABEL(fault)	| yes, just a regular fault
403	movl	%d0,%sp@-
404	jbsr	_C_LABEL(kgdb_trap_glue) | returns if no debugger
405	addl	#4,%sp
406#endif
407	moveq	#T_TRAP15,%d0
408	jra	_ASM_LABEL(fault)
409
410/*
411 * Hit a breakpoint (trap 1 or 2) instruction.
412 * Push the code and treat as a normal fault.
413 */
414ENTRY_NOPROFILE(trace)
415	clrl	%sp@-
416	moveml	%d0-%d7/%a0-%a7,%sp@-
417#ifdef KGDB
418	moveq	#T_TRACE,%d0
419	movw	%sp@(FR_HW),%d1		| get SSW
420	andw	#PSL_S,%d1		| from user mode?
421	jeq	_ASM_LABEL(fault)	| no, regular fault
422	movl	%d0,%sp@-
423	jbsr	_C_LABEL(kgdb_trap_glue) | returns if no debugger
424	addl	#4,%sp
425#endif
426	moveq	#T_TRACE,%d0
427	jra	_ASM_LABEL(fault)
428
429/* Use common m68k sigreturn */
430#include <m68k/m68k/sigreturn.s>
431
432/*
433 * Interrupt handlers.
434 *
435 *	Level 0:	Spurious: ignored.
436 *	Level 1:	builtin-RS232 TBE, softint (not used yet)
437 *	Level 2:	keyboard (CIA-A) + DMA + SCSI
438 *	Level 3:	VBL
439 *	Level 4:	not used
440 *	Level 5:	builtin-RS232 RBF
441 *	Level 6:	Clock (CIA-B-Timers), Floppy index pulse
442 *	Level 7:	Non-maskable: shouldn't be possible. ignore.
443 */
444
445/* Provide a generic interrupt dispatcher, only handle hardclock (int6)
446 * and serial RBF (int5) specially, to improve performance
447 */
448
449ENTRY_NOPROFILE(spurintr)
450	addql	#1,_C_LABEL(interrupt_depth)
451	addql	#1,_C_LABEL(intrcnt)+0
452	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
453	subql	#1,_C_LABEL(interrupt_depth)
454	jra	_ASM_LABEL(rei)
455
456ENTRY_NOPROFILE(lev5intr)
457	addql	#1,_C_LABEL(interrupt_depth)
458	moveml	%d0/%d1/%a0/%a1,%sp@-
459#include "ser.h"
460#if NSER > 0
461	jsr	_C_LABEL(ser_fastint)
462#else
463	INTREQWADDR(%a0)
464	movew	#INTF_RBF,%a0@		| clear RBF interrupt in intreq
465#endif
466	moveml	%sp@+,%d0/%d1/%a0/%a1
467	addql	#1,_C_LABEL(intrcnt)+20
468	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
469	subql	#1,_C_LABEL(interrupt_depth)
470	jra	_ASM_LABEL(rei)
471
472#ifdef DRACO
473ENTRY_NOPROFILE(DraCoLev2intr)
474	addql	#1,_C_LABEL(interrupt_depth)
475	moveml	%d0/%d1/%a0/%a1,%sp@-
476
477	CIAAADDR(%a0)
478	movb	%a0@(CIAICR),%d0	| read irc register (clears ints!)
479	jge     Ldrintrcommon		| CIAA IR not set, go through isr chain
480	movel	_C_LABEL(draco_intpen),%a0
481|	andib	#4,%a0@
482|XXX this would better be
483	bclr	#2,%a0@
484	btst	#0,%d0			| timerA interrupt?
485	jeq	Ldraciaend
486
487	lea	%sp@(16),%a1		| get pointer to PS
488	movl	%a1,%sp@-		| push pointer to PS, PC
489
490	movw	#PSL_HIGHIPL,%sr	| hardclock at high IPL
491	jbsr	_C_LABEL(hardclock)	| call generic clock int routine
492	addql	#4,%sp			| pop params
493	addql	#1,_C_LABEL(intrcnt)+32	| add another system clock interrupt
494
495Ldraciaend:
496	moveml	%sp@+,%d0/%d1/%a0/%a1
497	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
498	subql	#1,_C_LABEL(interrupt_depth)
499	jra	_ASM_LABEL(rei)
500
501/* XXX on the DraCo rev. 4 or later, lev 1 is vectored here. */
502ENTRY_NOPROFILE(DraCoLev1intr)
503	addql	#1,_C_LABEL(interrupt_depth)
504	moveml	%d0/%d1/%a0/%a1,%sp@-
505	movl	_C_LABEL(draco_ioct),%a0
506	btst	#5,%a0@(7)
507	jeq	Ldrintrcommon
508	btst	#4,%a0@(7)	| this only happens during autoconfiguration,
509	jeq	Ldrintrcommon	| so test last.
510	movw	#PSL_HIGHIPL,%sr	| run clock at high ipl
511Ldrclockretry:
512	lea	%sp@(16),%a1	| get pointer to PS
513	movl	%a1,%sp@-	| push pointer to PS, PC
514	jbsr	_C_LABEL(hardclock)
515	addql	#4,%sp		| pop params
516	addql	#1,_C_LABEL(intrcnt)+32	| add another system clock interrupt
517
518	movl	_C_LABEL(draco_ioct),%a0
519	tstb	%a0@(9)		| latch timer value
520	movw	%a0@(11),%d0	| can't use movpw here, might be 68060
521	movb	%a0@(13),%d0
522	addw	_C_LABEL(amiga_clk_interval)+2,%d0
523	movb	%d0,%a0@(13)	| low byte: latch write value
524	movw	%d0,%a0@(11)	| ...and write it into timer
525	tstw	%d0		| already positive?
526	jcs	Ldrclockretry	| we lost more than one tick, call us again.
527
528	clrb	%a0@(9)		| reset timer irq
529
530	moveml	%sp@+,%d0/%d1/%a0/%a1
531	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
532	subql	#1,_C_LABEL(interrupt_depth)
533	jra	_ASM_LABEL(rei)	| XXXX: shouldn't we call the normal lev1?
534
535/* XXX on the DraCo, lev 1, 3, 4, 5 and 6 are vectored here by initcpu() */
536ENTRY_NOPROFILE(DraCoIntr)
537	addql	#1,_C_LABEL(interrupt_depth)
538	moveml  %d0/%d1/%a0/%a1,%sp@-
539Ldrintrcommon:
540	lea	_ASM_LABEL(Drintrcnt)-4,%a0
541	movw	%sp@(22),%d0		| use vector offset
542	andw	#0xfff,%d0		|   sans frame type
543	addql	#1,%a0@(-0x60,%d0:w)	|     to increment apropos counter
544	movw	%sr,%sp@-		| push current SR value
545	clrw	%sp@-			|    padded to longword
546	jbsr	_C_LABEL(intrhand)	| handle interrupt
547	addql	#4,%sp			| pop SR
548	moveml	%sp@+,%d0/%d1/%a0/%a1
549	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
550	subql	#1,_C_LABEL(interrupt_depth)
551	jra	_ASM_LABEL(rei)
552#endif
553
554
555ENTRY_NOPROFILE(lev1intr)
556ENTRY_NOPROFILE(lev2intr)
557ENTRY_NOPROFILE(lev3intr)
558#ifndef LEV6_DEFER
559ENTRY_NOPROFILE(lev4intr)
560#endif
561	addql	#1,_C_LABEL(interrupt_depth)
562	moveml	%d0/%d1/%a0/%a1,%sp@-
563Lintrcommon:
564	lea	_C_LABEL(intrcnt),%a0
565	movw	%sp@(22),%d0		| use vector offset
566	andw	#0xfff,%d0		|   sans frame type
567	addql	#1,%a0@(-0x60,%d0:w)	|     to increment apropos counter
568	movw	%sr,%sp@-		| push current SR value
569	clrw	%sp@-			|    padded to longword
570	jbsr	_C_LABEL(intrhand)	| handle interrupt
571	addql	#4,%sp			| pop SR
572	moveml	%sp@+,%d0/%d1/%a0/%a1
573	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
574	subql	#1,_C_LABEL(interrupt_depth)
575	jra	_ASM_LABEL(rei)
576
577/* XXX used to be ifndef DRACO; vector will be overwritten by initcpu() */
578
579ENTRY_NOPROFILE(lev6intr)
580#ifdef LEV6_DEFER
581	/*
582	 * cause a level 4 interrupt (AUD3) to occur as soon
583	 * as we return. Block generation of level 6 ints until
584	 * we have dealt with this one.
585	 */
586	addql	#1,_C_LABEL(interrupt_depth)
587	moveml	%d0/%a0,%sp@-
588	INTREQRADDR(%a0)
589	movew	%a0@,%d0
590	btst	#INTB_EXTER,%d0
591	jeq	Llev6spur
592	INTREQWADDR(%a0)
593	movew	#INTF_SETCLR+INTF_AUD3,%a0@
594	INTENAWADDR(%a0)
595	movew	#INTF_EXTER,%a0@
596	movew	#INTF_SETCLR+INTF_AUD3,%a0@	| make sure THIS one is ok...
597	moveml	%sp@+,%d0/%a0
598	subql	#1,_C_LABEL(interrupt_depth)
599	rte
600Llev6spur:
601	addql	#1,_C_LABEL(intrcnt)+36	| count spurious level 6 interrupts
602	moveml	%sp@+,%d0/%a0
603	subql	#1,_C_LABEL(interrupt_depth)
604	rte
605
606ENTRY_NOPROFILE(lev4intr)
607ENTRY_NOPROFILE(fake_lev6intr)
608#endif
609	addql	#1,_C_LABEL(interrupt_depth)
610	moveml	%d0/%d1/%a0/%a1,%sp@-
611#ifdef LEV6_DEFER
612	/*
613	 * check for fake level 6
614	 */
615	INTREQRADDR(%a0)
616	movew	%a0@,%d0
617	btst	#INTB_EXTER,%d0
618	jeq	Lintrcommon		| if EXTER not pending, handle normally
619#endif
620
621	CIABADDR(%a0)
622	movb	%a0@(CIAICR),%d0	| read irc register (clears ints!)
623	jge	Lchkexter		| CIAB IR not set, go through isr chain
624	INTREQWADDR(%a0)
625#ifndef LEV6_DEFER
626	movew	#INTF_EXTER,%a0@	| clear EXTER interrupt in intreq
627#else
628	movew	#INTF_EXTER+INTF_AUD3,%a0@ | clear EXTER & AUD3 in intreq
629	INTENAWADDR(%a0)
630	movew	#INTF_SETCLR+INTF_EXTER,%a0@ | reenable EXTER interrupts
631#endif
632	btst	#0,%d0			| timerA interrupt?
633	jeq     Ltstciab4		| no
634	movl	%d0,%sp@-		| push CIAB interrupt flags
635	lea	%sp@(20),%a1		| get pointer to PS
636	movl	%a1,%sp@-		| push pointer to PS, PC
637	jbsr	_C_LABEL(hardclock)	| call generic clock int routine
638	addql	#4,%sp			| pop params
639	addql	#1,_C_LABEL(intrcnt)+32	| add another system clock interrupt
640	movl	%sp@+,%d0		| pop interrupt flags
641Ltstciab4:
642#include "fd.h"
643#if NFD > 0
644	btst	#4,%d0			| FLG (dskindex) interrupt?
645	jeq	Lskipciab		| no
646	jbsr	_C_LABEL(fdidxintr)	| tell floppy driver we got it
647Lskipciab:
648#endif
649| other ciab interrupts?
650Llev6done:
651	moveml	%sp@+,%d0/%d1/%a0/%a1	| restore scratch regs
652	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
653	subql	#1,_C_LABEL(interrupt_depth)
654	jra	_ASM_LABEL(rei)		| all done [can we do rte here?]
655Lchkexter:
656| check to see if EXTER request is really set?
657	movl	_C_LABEL(isr_exter),%a0	| get head of EXTER isr chain
658Lnxtexter:
659	movl	%a0,%d0			| test if any more entries
660	jeq	Lexterdone		| (spurious interrupt?)
661	movl	%a0,%sp@-		| save isr pointer
662	movl	%a0@(ISR_ARG),%sp@-
663	movl	%a0@(ISR_INTR),%a0
664	jsr	%a0@			| call isr handler
665	addql	#4,%sp
666	movl	%sp@+,%a0		| restore isr pointer
667	movl	%a0@(ISR_FORW),%a0	| get next pointer
668	tstl	%d0			| did handler process the int?
669	jeq	Lnxtexter		| no, try next
670Lexterdone:
671	INTREQWADDR(%a0)
672#ifndef LEV6_DEFER
673	movew	#INTF_EXTER,%a0@	| clear EXTER interrupt
674#else
675	movew	#INTF_EXTER+INTF_AUD3,%a0@ | clear EXTER & AUD3 interrupt
676	INTENAWADDR(%a0)
677	movew	#INTF_SETCLR+INTF_EXTER,%a0@ | reenable EXTER interrupts
678#endif
679	addql	#1,_C_LABEL(intrcnt)+24	| count EXTER interrupts
680	jra	Llev6done
681/* XXX endifndef DRACO used to be here */
682
683ENTRY_NOPROFILE(lev7intr)
684	addql	#1,_C_LABEL(intrcnt)+28
685	/*
686	 * some amiga zorro2 boards seem to generate spurious NMIs. Best
687	 * thing to do is to return as quick as possible. That's the
688	 * reason why I do RTE here instead of jra rei.
689	 */
690	rte				| all done
691
692
693/*
694 * Emulation of VAX REI instruction.
695 *
696 * This code deals with checking for and servicing ASTs
697 * (profiling, scheduling) and software interrupts (network, softclock).
698 * We check for ASTs first, just like the VAX.  To avoid excess overhead
699 * the T_ASTFLT handling code will also check for software interrupts so we
700 * do not have to do it here.
701 * do not have to do it here.  After identifing that we need an AST we
702 * drop the IPL to allow device interrupts.
703 *
704 * This code is complicated by the fact that sendsig may have been called
705 * necessitating a stack cleanup.  A cleanup should only be needed at this
706 * point for coprocessor mid-instruction frames (type 9), but we also test
707 * for bus error frames (type 10 and 11).
708 */
709ASENTRY_NOPROFILE(rei)
710#ifdef DEBUG
711	tstl	_C_LABEL(panicstr)	| have we paniced?
712	jne	Ldorte			| yes, do not make matters worse
713#endif
714	tstl	_C_LABEL(astpending)	| AST pending?
715	jeq	Ldorte			| no, done
716Lrei1:
717	btst	#5,%sp@			| yes, are we returning to user mode?
718	jne	Ldorte			| no, done
719	movw	#PSL_LOWIPL,%sr		| lower SPL
720	clrl	%sp@-			| stack adjust
721	moveml	%d0-%d7/%a0-%a7,%sp@-	| save all registers
722	movl	%usp,%a1		| including
723	movl	%a1,%sp@(FR_SP)		|    the users SP
724	clrl	%sp@-			| VA == none
725	clrl	%sp@-			| code == none
726	movl	#T_ASTFLT,%sp@-		| type == async system trap
727	jbsr	_C_LABEL(trap)		| go handle it
728	lea	%sp@(12),%sp		| pop value args
729	movl	%sp@(FR_SP),%a0		| restore user SP
730	movl	%a0,%usp		|   from save area
731	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
732	jne	Laststkadj		| yes, go to it
733	moveml	%sp@+,%d0-%d7/%a0-%a6	| no, restore most user regs
734	addql	#8,%sp			| toss SP and stack adjust
735	rte				| and do real RTE
736Laststkadj:
737	lea	%sp@(FR_HW),%a1		| pointer to HW frame
738	addql	#8,%a1			| source pointer
739	movl	%a1,%a0			| source
740	addw	%d0,%a0			|  + hole size = dest pointer
741	movl	%a1@-,%a0@-		| copy
742	movl	%a1@-,%a0@-		|  8 bytes
743	movl	%a0,%sp@(FR_SP)		| new SSP
744	moveml	%sp@+,%d0-%d7/%a0-%a6	| restore user registers
745	movl	%sp@,%sp		| and our SP
746Ldorte:
747	rte				| real return
748
749/*
750 * Kernel access to the current processes kernel stack is via a fixed
751 * virtual address.  It is at the same address as in the users VA space.
752 */
753BSS(esym,4)
754
755
756/*
757 * Initialization
758 *
759 * A5 contains physical load point from boot
760 * exceptions vector thru our table, that's bad.. just hope nothing exceptional
761 * happens till we had time to initialize ourselves..
762 */
763BSS(lowram,4)
764
765#define	RELOC(var, ar)			\
766	lea	_C_LABEL(var),ar;	\
767	addl	%a5,ar
768
769#define	ASRELOC(var, ar)		\
770	lea	_ASM_LABEL(var),ar;	\
771	addl	%a5,ar
772
773	.text
774
775	| XXX should be a symbol?
776	| 2: needs a4 = esym
777	| 3: no chipmem requirement
778	|    bootinfo data structure
779
780	.word	0
781	.word	0x0003			| loadbsd version required
782ASENTRY_NOPROFILE(start)
783	lea	%pc@(L_base),%a5	| initialize relocation register
784
785	movw	#PSL_HIGHIPL,%sr	| no interrupts
786	ASRELOC(tmpstk,%a6)
787	movl	%a6,%sp			| give ourselves a temporary stack
788
789	| save the passed parameters. "prepass" them on the stack for
790	| later catch by start_c()
791	movl	%d6,%sp@-		| pass boot partition offset
792	movl	%a2,%sp@-		| pass sync inhibit flags
793	movl	%d3,%sp@-		| pass AGA mode
794	movl	%a4,%sp@-		| pass address of _esym
795	movl	%d1,%sp@-		| pass chipmem-size
796	movl	%d0,%sp@-		| pass fastmem-size
797	movl	%a0,%sp@-		| pass fastmem_start
798	movl	%d5,%sp@-		| pass machine id
799
800	/*
801	 * initialize some hw addresses to their physical address
802	 * for early running
803	 */
804#ifdef DRACO
805	/*
806	 * this is already dynamically done on DraCo
807	 */
808	cmpb	#0x7D,%sp@
809	jne	LisAmiga1
810| debug code:
811| we should need about 1 uSec for the loop.
812| we dont need the AGA mode register.
813	movel	#100000,%d3
814LisDraco0:
815#ifdef DEBUG_KERNEL_START
816	movb	#0,0x200003c8
817	movb	#00,0x200003c9
818	movb	#40,0x200003c9
819	movb	#00,0x200003c9
820|XXX:
821	movb	#0,0x200003c8
822	movb	#40,0x200003c9
823	movb	#00,0x200003c9
824	movb	#00,0x200003c9
825	subql	#1,%d3
826	jcc	LisDraco0
827#endif
828
829	RELOC(chipmem_start, %a0)
830	movl	#0,%a0@
831
832	RELOC(CIAAbase, %a0)
833	movl	#0x2801001, %a0@
834	RELOC(CIABbase, %a0)
835	movl	#0x2800000, %a0@
836
837	/* XXXX more to come here; as we need it */
838
839	jra	LisDraco1
840LisAmiga1:
841#endif
842	RELOC(chipmem_start, %a0)
843	movl	#0x400,%a0@
844	RELOC(CIAAbase, %a0)
845	movl	#0xbfe001,%a0@
846	RELOC(CIABbase, %a0)
847	movl	#0xbfd000,%a0@
848	RELOC(CUSTOMbase, %a0)
849	movl	#0xdff000,%a0@
850
851#ifdef DRACO
852LisDraco1:
853#endif
854	/*
855	 * initialize the timer frequency
856	 */
857	RELOC(eclockfreq, %a0)
858	movl	%d4,%a0@
859
860	movl	#AMIGA_68030,%d1	| 68030 Attn flag from exec
861	andl	%d5,%d1
862	jeq	Ltestfor020
863	RELOC(mmutype, %a0)
864	movl	#MMU_68030,%a0@		| assume 020 means 851
865	RELOC(cputype, %a0)
866	movl	#CPU_68030,%a0@
867	jra	Lsetcpu040		| skip to init.
868Ltestfor020:
869	movl	#AMIGA_68020,%d1	| 68020 Attn flag from exec
870	andl	%d5,%d1
871	jeq	Lsetcpu040
872	RELOC(mmutype, %a0)
873	movl	#MMU_68851,%a0@
874	RELOC(cputype, %a0)
875	movl	#CPU_68020,%a0@
876Lsetcpu040:
877	movl	#CACHE_OFF,%d0		| 68020/030 cache
878	movl	#AMIGA_68040,%d1
879	andl	%d1,%d5
880	jeq	Lstartnot040		| it is not 68040
881	RELOC(mmutype, %a0)
882	movl	#MMU_68040,%a0@		| same as hp300 for compat
883	RELOC(cputype, %a0)
884	movl	#CPU_68040,%a0@
885	.word	0xf4f8			| cpusha bc - push and invalidate caches
886	movl	#CACHE40_OFF,%d0	| 68040 cache disable
887#ifndef BB060STUPIDROM
888	btst	#7,%sp@(3)
889	jeq	Lstartnot040
890	movl	#CPU_68060,%a0@		| and in the cputype
891	orl	#IC60_CABC,%d0		| XXX and clear all 060 branch cache
892#else
893	movc	%d0,%cacr
894	bset	#30,%d0			| not allocate data cache bit
895	movc	%d0,%cacr		| does it stick?
896	movc	%cacr,%d0
897	tstl	%d0
898	jeq	Lstartnot040
899	bset	#7,%sp@(3)		| note it is '60 family in machineid
900	movl	#CPU_68060,%a0@		| and in the cputype
901	orl	#IC60_CABC,%d0		| XXX and clear all 060 branch cache
902	.word	0x4e7a,0x1808		| movc	pcr,d1
903	swap	%d1
904	cmpw	#0x430,%d1
905	jne	Lstartnot040		| but no FPU
906	bset	#6,%sp@(3)		| yes, we have FPU, note that
907	swap	%d1
908	bclr	#1,%d1			| ... and switch it on.
909	.word	0x4e7b,0x1808		| movc	d1,pcr
910#endif
911Lstartnot040:
912	movc	%d0,%cacr		| clear and disable on-chip cache(s)
913	movl	#_C_LABEL(vectab),%a0
914	movc	%a0,%vbr
915
916/* initialize source/destination control registers for movs */
917	moveq	#FC_USERD,%d0		| user space
918	movc	%d0,%sfc		|   as source
919	movc	%d0,%dfc		|   and destination of transfers
920
921/* let the C function initialize everything and enable the MMU */
922	RELOC(start_c, %a0)
923	jbsr	%a0@
924	addl	#28,%sp
925	jmp	Lunshadow:l
926
927Lunshadow:
928
929	lea	_ASM_LABEL(tmpstk),%sp	| give ourselves a temporary stack
930	jbsr	_C_LABEL(start_c_cleanup)
931
932/* set kernel stack, user SP, and initial pcb */
933	movl	_C_LABEL(proc0paddr),%a1	| proc0 kernel stack
934	lea	%a1@(USPACE),%sp	| set kernel stack to end of area
935	lea	_C_LABEL(proc0),%a2	| initialize proc0.p_addr so that
936	movl	%a1,%a2@(P_ADDR)	|   we don't dref NULL in trap()
937	movl	#USRSTACK-4,%a2
938	movl	%a2,%usp		| init user SP
939	movl	%a2,%a1@(PCB_USP)	| and save it
940	movl	%a1,_C_LABEL(curpcb)	| proc0 is running
941	clrw	%a1@(PCB_FLAGS)		| clear flags
942#ifdef FPCOPROC
943	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
944|WRONG!	movl	%a1,%sp@-
945|	pea	%a1@(PCB_FPCTX)
946|	jbsr	_C_LABEL(m68881_restore)	| restore it (does not kill a1)
947|	addql	#4,%sp
948#endif
949/* flush TLB and turn on caches */
950
951	jbsr	_C_LABEL(_TBIA)		| invalidate TLB
952	movl	#CACHE_ON,%d0
953	tstl	%d5
954	jeq	Lcacheon
955| is this needed? MLH
956	.word	0xf4f8			| cpusha bc - push & invalidate caches
957	movl	#CACHE40_ON,%d0
958#ifdef M68060
959	cmpl	#CPU_68060,_C_LABEL(cputype)
960	jne	Lcacheon
961	movl	#CACHE60_ON,%d0
962#endif
963Lcacheon:
964	movc	%d0,%cacr		| clear cache(s)
965/* final setup for C code */
966
967	movw	#PSL_LOWIPL,%sr		| lower SPL
968
969	movl	%d7,_C_LABEL(boothowto)	| save reboot flags
970/*
971 * Create a fake exception frame that returns to user mode,
972 * make space for the rest of a fake saved register set, and
973 * pass the first available RAM and a pointer to the register
974 * set to "main()".  "main()" will do an "execve()" using that
975 * stack frame.
976 * When "main()" returns, we're running in process 1 and have
977 * successfully executed the "execve()".  We load up the registers from
978 * that set; the "rte" loads the PC and PSR, which jumps to "init".
979 */
980  	clrw	%sp@-			| vector offset/frame type
981	clrl	%sp@-			| PC - filled in by "execve"
982  	movw	#PSL_USER,%sp@-		| in user mode
983	clrl	%sp@-			| stack adjust count
984	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
985	lea	_C_LABEL(proc0),%a0		| proc0 in a0
986	movl	%sp,%a0@(P_MD + MD_REGS)	| save frame for proc0
987	movl	%usp,%a1
988	movl	%a1,%sp@(FR_SP)		| save user stack pointer in frame
989	pea	%sp@			| addr of space for D0
990
991	jbsr	_C_LABEL(main)		| main(firstaddr, r0)
992	addql	#4,%sp			| pop args
993
994	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
995	jne	Lnoflush		| no, skip
996	.word	0xf478			| cpusha dc
997	.word	0xf498			| cinva ic, also clears the 060 btc
998Lnoflush:
999	movl	%sp@(FR_SP),%a0		| grab and load
1000	movl	%a0,%usp		|   user SP
1001	moveml	%sp@+,%d0-%d7/%a0-%a6	| load most registers (all but SSP)
1002	addql	#8,%sp			| pop SSP and stack adjust count
1003  	rte
1004
1005/*
1006 * proc_trampoline call function in register a2 with a3 as an arg
1007 * and then rei.
1008 */
1009ENTRY_NOPROFILE(proc_trampoline)
1010	movl	%a3,%sp@-		| push function arg
1011	jbsr	%a2@			| call function
1012	addql	#4,%sp			| pop arg
1013	movl	%sp@(FR_SP),%a0		| usp to a0
1014	movl	%a0,%usp		| setup user stack pointer
1015	moveml	%sp@+,%d0-%d7/%a0-%a6	| restore all but sp
1016	addql	#8,%sp			| pop sp and stack adjust
1017	jra	_ASM_LABEL(rei)		| all done
1018
1019/*
1020 * Use common m68k sigcode.
1021 */
1022#include <m68k/m68k/sigcode.s>
1023#ifdef COMPAT_SUNOS
1024#include <m68k/m68k/sunos_sigcode.s>
1025#endif
1026#ifdef COMPAT_SVR4
1027#include <m68k/m68k/svr4_sigcode.s>
1028#endif
1029
1030/*
1031 * Primitives
1032 */
1033
1034/*
1035 * Use common m68k support routines.
1036 */
1037#include <m68k/m68k/support.s>
1038
1039/*
1040 * update profiling information for the user
1041 * addupc(pc, &u.u_prof, ticks)
1042 */
1043ENTRY(addupc)
1044	movl	%a2,%sp@-		| scratch register
1045	movl	%sp@(12),%a2		| get &u.u_prof
1046	movl	%sp@(8),%d0		| get user pc
1047	subl	%a2@(8),%d0		| pc -= pr->pr_off
1048	jlt	Lauexit			| less than 0, skip it
1049	movl	%a2@(12),%d1		| get pr->pr_scale
1050	lsrl	#1,%d0			| pc /= 2
1051	lsrl	#1,%d1			| scale /= 2
1052	mulul	%d1,%d0			| pc /= scale
1053	moveq	#14,%d1
1054	lsrl	%d1,%d0			| pc >>= 14
1055	bclr	#0,%d0			| pc &= ~1
1056	cmpl	%a2@(4),%d0		| too big for buffer?
1057	jge	Lauexit			| yes, screw it
1058	addl	%a2@,%d0		| no, add base
1059	movl	%d0,%sp@-		| push address
1060	jbsr	_C_LABEL(fusword)	| grab old value
1061	movl	%sp@+,%a0		| grab address back
1062	cmpl	#-1,%d0			| access ok
1063	jeq	Lauerror		| no, skip out
1064	addw	%sp@(18),%d0		| add tick to current value
1065	movl	%d0,%sp@-		| push value
1066	movl	%a0,%sp@-		| push address
1067	jbsr	_C_LABEL(susword)	| write back new value
1068	addql	#8,%sp			| pop params
1069	tstl	%d0			| fault?
1070	jeq	Lauexit			| no, all done
1071Lauerror:
1072	clrl	%a2@(12)		| clear scale (turn off prof)
1073Lauexit:
1074	movl	%sp@+,%a2		| restore scratch reg
1075	rts
1076
1077/*
1078 * non-local gotos
1079 */
1080ENTRY(qsetjmp)
1081	movl	%sp@(4),%a0	| savearea pointer
1082	lea	%a0@(40),%a0	| skip regs we do not save
1083	movl	%a6,%a0@+	| save FP
1084	movl	%sp,%a0@+	| save SP
1085	movl	%sp@,%a0@	| and return address
1086	moveq	#0,%d0		| return 0
1087	rts
1088
1089BSS(want_resched,4)
1090
1091/*
1092 * Use common m68k process manipulation routines.
1093 */
1094#include <m68k/m68k/proc_subr.s>
1095
1096Lsw0:
1097	.asciz	"cpu_switch"
1098	.even
1099
1100	.data
1101GLOBAL(masterpaddr)		| XXX compatibility (debuggers)
1102GLOBAL(curpcb)
1103	.long	0
1104ASGLOBAL(pcbflag)
1105	.byte	0		| copy of pcb_flags low byte
1106#ifdef __ELF__
1107	.align	4
1108#else
1109	.align	2
1110#endif
1111BSS(nullpcb,SIZEOF_PCB)
1112	.text
1113
1114/*
1115 * At exit of a process, do a switch for the last time.
1116 * Switch to a safe stack and PCB, and select a new process to run.  The
1117 * old stack and u-area will be freed by the reaper.
1118 *
1119 * MUST BE CALLED AT SPLHIGH!
1120 */
1121ENTRY(switch_exit)
1122	movl	%sp@(4),%a0
1123	movl	#_C_LABEL(nullpcb),_C_LABEL(curpcb) | save state in garbage pcb
1124	lea	_ASM_LABEL(tmpstk),%sp	| goto a tmp stack
1125
1126	/* Schedule the vmspace and stack to be freed. */
1127	movl	%a0,%sp@-		| exit2(p)
1128	jbsr	_C_LABEL(exit2)
1129	lea	%sp@(4),%sp		| pop args
1130
1131#if defined(LOCKDEBUG)
1132	/* Acquire sched_lock */
1133	jbsr	_C_LABEL(sched_lock_idle)
1134#endif
1135
1136	jra	_C_LABEL(cpu_switch)
1137
1138/*
1139 * When no processes are on the runq, Swtch branches to idle
1140 * to wait for something to come ready.
1141 */
1142ASENTRY_NOPROFILE(Idle)
1143#if defined(LOCKDEBUG)
1144	/* Release sched_lock */
1145	jbsr	_C_LABEL(sched_unlock_idle)
1146#endif
1147	stop	#PSL_LOWIPL
1148	movw	#PSL_HIGHIPL,%sr
1149#if defined(LOCKDEBUG)
1150	/* Acquire sched_lock */
1151	jbsr	_C_LABEL(sched_lock_idle)
1152#endif
1153	movl	_C_LABEL(sched_whichqs),%d0
1154	jeq	_ASM_LABEL(Idle)
1155	jra	Lsw1
1156
1157Lbadsw:
1158	movl	#Lsw0,%sp@-
1159	jbsr	_C_LABEL(panic)
1160	/*NOTREACHED*/
1161
1162/*
1163 * Cpu_switch()
1164 *
1165 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
1166 * entire ATC.  The effort involved in selective flushing may not be
1167 * worth it, maybe we should just flush the whole thing?
1168 *
1169 * NOTE 2: With the new VM layout we now no longer know if an inactive
1170 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1171 * bit).  For now, we just always flush the full ATC.
1172 */
1173ENTRY(cpu_switch)
1174	movl	_C_LABEL(curpcb),%a0	| current pcb
1175	movw	%sr,%a0@(PCB_PS)	| save sr before changing ipl
1176#ifdef notyet
1177	movl	_C_LABEL(curproc),%sp@-	| remember last proc running
1178#endif
1179	clrl	_C_LABEL(curproc)
1180
1181	/*
1182	 * Find the highest-priority queue that isn't empty,
1183	 * then take the first proc from that queue.
1184	 */
1185	movl	_C_LABEL(sched_whichqs),%d0
1186	jeq	_ASM_LABEL(Idle)
1187Lsw1:
1188	/*
1189	 * Interrupts are blocked, sched_lock is held.  If
1190	 * we come here via Idle, %d0 contains the contents
1191	 * of a non-zero sched_whichqs.
1192	 */
1193	movl	%d0,%d1
1194	negl	%d0
1195	andl	%d1,%d0
1196	bfffo	%d0{#0:#32},%d1
1197	eorib	#31,%d1
1198
1199	movl	%d1,%d0
1200	lslb	#3,%d1			| convert queue number to index
1201	addl	#_C_LABEL(sched_qs),%d1	| locate queue (q)
1202	movl	%d1,%a1
1203	movl	%a1@(P_FORW),%a0	| p = q->p_forw
1204	cmpal	%d1,%a0			| anyone on queue?
1205	jeq	Lbadsw			| no, panic
1206#ifdef DIAGNOSTIC
1207	tstl	%a0@(P_WCHAN)
1208	jne	Lbadsw
1209	cmpb	#SRUN,%a0@(P_STAT)
1210	jne	Lbadsw
1211#endif
1212	movl	%a0@(P_FORW),%a1@(P_FORW)	| q->p_forw = p->p_forw
1213	movl	%a0@(P_FORW),%a1		| n = p->p_forw
1214	movl	%a0@(P_BACK),%a1@(P_BACK)	| n->p_back = q
1215	cmpal	%d1,%a1			| anyone left on queue?
1216	jne	Lsw2			| yes, skip
1217	movl	_C_LABEL(sched_whichqs),%d1
1218	bclr	%d0,%d1			| no, clear bit
1219	movl	%d1,_C_LABEL(sched_whichqs)
1220Lsw2:
1221	/* p->p_cpu initialized in fork1() for single-processor */
1222	movb	#SONPROC,%a0@(P_STAT)		| p->p_stat = SONPROC
1223	movl	%a0,_C_LABEL(curproc)
1224	clrl	_C_LABEL(want_resched)
1225#ifdef notyet
1226	movl	%sp@+,%a1
1227	cmpl	%a0,%a1				| switching to same proc?
1228	jeq	Lswdone				| yes, skip save and restore
1229#endif
1230	/*
1231	 * Save state of previous process in its pcb.
1232	 */
1233	movl	_C_LABEL(curpcb),%a1
1234	moveml	%d2-%d7/%a2-%a7,%a1@(PCB_REGS)	| save non-scratch registers
1235	movl	%usp,%a2			| grab USP (a2 has been saved)
1236	movl	%a2,%a1@(PCB_USP)		| and save it
1237	movl	_C_LABEL(CMAP2),%a1@(PCB_CMAP2)	| save temporary map PTE
1238#ifdef FPCOPROC
1239#ifdef FPU_EMULATE
1240	tstl	_C_LABEL(fputype)		| do we have any FPU?
1241	jeq	Lswnofpsave			| no, dont save
1242#endif
1243	lea	%a1@(PCB_FPCTX),%a2		| pointer to FP save area
1244	fsave	%a2@				| save FP state
1245#if defined(M68020) || defined(M68030) || defined(M68040)
1246#ifdef M68060
1247	cmpl	#CPU_68060,_C_LABEL(cputype)
1248	jeq	Lsavfp60
1249#endif
1250	tstb	%a2@				| null state frame?
1251	jeq	Lswnofpsave			| yes, all done
1252	fmovem	%fp0-%fp7,%a2@(FPF_REGS)	| save FP general registers
1253	fmovem	%fpcr/%fpsr/%fpi,%a2@(FPF_FPCR)	| save FP control registers
1254#ifdef M68060
1255	jra	Lswnofpsave
1256#endif
1257#endif
1258#ifdef M68060
1259Lsavfp60:
1260	tstb	%a2@(2)				| null state frame?
1261	jeq	Lswnofpsave			| yes, all done
1262	fmovem	%fp0-%fp7,%a2@(FPF_REGS)	| save FP general registers
1263	fmovem	%fpcr,%a2@(FPF_FPCR)		| save FP control registers
1264	fmovem	%fpsr,%a2@(FPF_FPSR)
1265	fmovem	%fpi,%a2@(FPF_FPI)
1266#endif
1267Lswnofpsave:
1268#endif
1269
1270	clrl	%a0@(P_BACK)			| clear back link
1271	movl	%a0@(P_ADDR),%a1		| get p_addr
1272	movl	%a1,_C_LABEL(curpcb)
1273	movb	%a1@(PCB_FLAGS+1),_ASM_LABEL(pcbflag) | copy of pcb_flags low byte
1274
1275#if defined(LOCKDEBUG)
1276	/*
1277	 * Done mucking with the run queues, release the
1278	 * scheduler lock, but keep interrupts out.
1279	 */
1280	movl	%a0,sp@-			| not args...
1281	movl	%a1,sp@-			| ...just saving
1282	jbsr	_C_LABEL(sched_unlock_idle)
1283	movl	sp@+,%a1
1284	movl	sp@+,%a0
1285#endif
1286
1287	/*
1288	 * Activate process's address space.
1289	 * XXX Should remember the last USTP value loaded, and call this
1290	 * XXX only if it has changed.
1291	 */
1292	pea	%a0@				| push proc
1293	jbsr	_C_LABEL(pmap_activate)		| pmap_activate(p)
1294	addql	#4,%sp
1295	movl	_C_LABEL(curpcb),%a1		| restore p_addr
1296
1297	lea	_ASM_LABEL(tmpstk),%sp		| now goto a tmp stack for NMI
1298
1299	movl	%a1@(PCB_CMAP2),_C_LABEL(CMAP2)	| reload tmp map
1300	moveml	%a1@(PCB_REGS),%d2-%d7/%a2-%a7	| and registers
1301	movl	%a1@(PCB_USP),%a0
1302	movl	%a0,%usp			| and USP
1303#ifdef FPCOPROC
1304#ifdef FPU_EMULATE
1305	tstl	_C_LABEL(fputype)		| do we _have_ any fpu?
1306	jne	Lresnonofpatall
1307	movw	%a1@(PCB_PS),%sr		| no, restore PS
1308	moveq	#1,%d0				| return 1 (for alternate rets)
1309	rts
1310Lresnonofpatall:
1311#endif
1312	lea	%a1@(PCB_FPCTX),%a0		| pointer to FP save area
1313#if defined(M68020) || defined(M68030) || defined(M68040)
1314#ifdef M68060
1315	cmpl	#CPU_68060,_C_LABEL(cputype)
1316	jeq	Lresfp60rest1
1317#endif
1318	tstb	%a0@				| null state frame?
1319	jeq	Lresfprest2			| yes, easy
1320	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi	| restore FP control registers
1321	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general registers
1322Lresfprest2:
1323	frestore %a0@				| restore state
1324	movw	%a1@(PCB_PS),%sr		| no, restore PS
1325	moveq	#1,%d0				| return 1 (for alternate rets)
1326	rts
1327#endif
1328
1329#ifdef M68060
1330Lresfp60rest1:
1331	tstb	%a0@(2)				| null state frame?
1332	jeq	Lresfp60rest2			| yes, easy
1333	fmovem	%a0@(FPF_FPCR),%fpcr		| restore FP control registers
1334	fmovem	%a0@(FPF_FPSR),%fpsr
1335	fmovem	%a0@(FPF_FPI),%fpi
1336	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general registers
1337Lresfp60rest2:
1338	frestore %a0@				| restore state
1339	movw	%a1@(PCB_PS),%sr		| no, restore PS
1340	moveq	#1,%d0				| return 1 (for alternate rets)
1341	rts
1342#endif
1343#endif
1344
1345/*
1346 * savectx(pcb)
1347 * Update pcb, saving current processor state
1348 */
1349ENTRY(savectx)
1350	movl	%sp@(4),%a1
1351	movw	%sr,%a1@(PCB_PS)
1352	movl	%usp,%a0			| grab USP
1353	movl	%a0,%a1@(PCB_USP)			| and save it
1354	moveml	%d2-%d7/%a2-%a7,%a1@(PCB_REGS)	| save non-scratch registers
1355	movl	_C_LABEL(CMAP2),%a1@(PCB_CMAP2)	| save temporary map PTE
1356#ifdef FPCOPROC
1357#ifdef FPU_EMULATE
1358	tstl	_C_LABEL(fputype)
1359	jeq	Lsavedone
1360#endif
1361	lea	%a1@(PCB_FPCTX),%a0		| pointer to FP save area
1362	fsave	%a0@				| save FP state
1363#if defined(M68020) || defined(M68030) || defined(M68040)
1364#ifdef M68060
1365	cmpl	#CPU_68060,_C_LABEL(cputype)
1366	jeq	Lsavctx60
1367#endif
1368	tstb	%a0@				| null state frame?
1369	jeq	Lsavedone			| yes, all done
1370	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
1371	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR)	| save FP control registers
1372#ifdef	M68060
1373	moveq	#0,%d0
1374	rts
1375#endif
1376#endif
1377#ifdef	M68060
1378Lsavctx60:
1379	tstb	%a0@(2)
1380	jeq	Lsavedone
1381	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
1382	fmovem	%fpcr,%a0@(FPF_FPCR)		| save FP control registers
1383	fmovem	%fpsr,%a0@(FPF_FPSR)
1384	fmovem	%fpi,%a0@(FPF_FPI)
1385#endif
1386#endif
1387Lsavedone:
1388	moveq	#0,%d0				| return 0
1389	rts
1390
1391ENTRY(ecacheon)
1392	rts
1393
1394ENTRY(ecacheoff)
1395	rts
1396
1397/*
1398 * Get callers current SP value.
1399 * Note that simply taking the address of a local variable in a C function
1400 * doesn't work because callee saved registers may be outside the stack frame
1401 * defined by A6 (e.g. GCC generated code).
1402 */
1403ENTRY(getsp)
1404	movl	%sp,%d0				| get current SP
1405	addql	#4,%d0				| compensate for return address
1406	movl	%d0,%a0				| Comply with ELF ABI
1407	rts
1408
1409ENTRY(getsfc)
1410	movc	%sfc,%d0
1411	rts
1412ENTRY(getdfc)
1413	movc	%dfc,%d0
1414	rts
1415
1416/*
1417 * Check out a virtual address to see if it's okay to write to.
1418 *
1419 * probeva(va, fc)
1420 *
1421 */
1422ENTRY(probeva)
1423	movl	%sp@(8),%d0
1424	movec	%d0,%dfc
1425	movl	%sp@(4),%a0
1426	.word	0xf548				| ptestw (a0)
1427	moveq	#FC_USERD,%d0			| restore DFC to user space
1428	movc	%d0,%dfc
1429	.word	0x4e7a,0x0805			| movec  MMUSR,d0
1430	rts
1431
1432/*
1433 * Load a new user segment table pointer.
1434 */
1435ENTRY(loadustp)
1436	movl	%sp@(4),%d0			| new USTP
1437	moveq	#PGSHIFT,%d1
1438	lsll	%d1,%d0				| convert to addr
1439#ifdef M68060
1440	cmpl	#CPU_68060,_C_LABEL(cputype)	| 68060?
1441	jeq	Lldustp060			|  yes, skip
1442#endif
1443	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
1444	jeq	Lldustp040			|  yes, skip
1445	pflusha					| flush entire TLB
1446	lea	_C_LABEL(protorp),%a0		| CRP prototype
1447	movl	%d0,%a0@(4)			| stash USTP
1448	pmove	%a0@,%crp			| load root pointer
1449	movl	#CACHE_CLR,%d0
1450	movc	%d0,%cacr			| invalidate cache(s)
1451	rts
1452#ifdef M68060
1453Lldustp060:
1454	movc	%cacr,%d1
1455	orl	#IC60_CUBC,%d1			| clear user btc entries
1456	movc	%d1,%cacr
1457#endif
1458Lldustp040:
1459	.word	0xf518				| pflusha
1460	.word	0x4e7b,0x0806			| movec d0,URP
1461	rts
1462
1463/*
1464 * Flush any hardware context associated with given USTP.
1465 * Only does something for HP330 where we must flush RPT
1466 * and ATC entries in PMMU.
1467 */
1468ENTRY(flushustp)
1469#ifdef M68060
1470	cmpl	#CPU_68060,_C_LABEL(cputype)
1471	jeq	Lflustp060
1472#endif
1473	cmpl	#MMU_68040,_C_LABEL(mmutype)
1474	jeq	Lnot68851
1475	tstl	_C_LABEL(mmutype)		| 68851 PMMU?
1476	jle	Lnot68851			| no, nothing to do
1477	movl	%sp@(4),%d0			| get USTP to flush
1478	moveq	#PGSHIFT,%d1
1479	lsll	%d1,%d0				| convert to address
1480	movl	%d0,_C_LABEL(protorp)+4		| stash USTP
1481	pflushr	_C_LABEL(protorp)		| flush RPT/TLB entries
1482Lnot68851:
1483	rts
1484#ifdef M68060
1485Lflustp060:
1486	movc	%cacr,%d1
1487	orl	#IC60_CUBC,%d1			| clear user btc entries
1488	movc	%d1,%cacr
1489	rts
1490#endif
1491
1492
1493ENTRY(ploadw)
1494	movl	%sp@(4),%a0			| address to load
1495	cmpl	#MMU_68040,_C_LABEL(mmutype)
1496	jeq	Lploadw040
1497	ploadw	#1,%a0@				| pre-load translation
1498Lploadw040:					| should 68040 do a ptest?
1499	rts
1500
1501#ifdef FPCOPROC
1502/*
1503 * Save and restore 68881 state.
1504 * Pretty awful looking since our assembler does not
1505 * recognize FP mnemonics.
1506 */
1507ENTRY(m68881_save)
1508	movl	%sp@(4),%a0			| save area pointer
1509	fsave	%a0@				| save state
1510#if defined(M68020) || defined(M68030) || defined(M68040)
1511#ifdef M68060
1512	cmpl	#CPU_68060,_C_LABEL(cputype)
1513	jeq	Lm68060fpsave
1514#endif
1515	tstb	%a0@				| null state frame?
1516	jeq	Lm68881sdone			| yes, all done
1517	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
1518	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR)	| save FP control registers
1519Lm68881sdone:
1520	rts
1521#endif
1522
1523#ifdef M68060
1524Lm68060fpsave:
1525	tstb	%a0@(2)				| null state frame?
1526	jeq	Lm68060sdone			| yes, all done
1527	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
1528	fmovem	%fpcr,%a0@(FPF_FPCR)		| save FP control registers
1529	fmovem	%fpsr,%a0@(FPF_FPSR)
1530	fmovem	%fpi,%a0@(FPF_FPI)
1531Lm68060sdone:
1532	rts
1533#endif
1534
1535ENTRY(m68881_restore)
1536	movl	%sp@(4),%a0			| save area pointer
1537#if defined(M68020) || defined(M68030) || defined(M68040)
1538#if defined(M68060)
1539	cmpl	#CPU_68060,_C_LABEL(cputype)
1540	jeq	Lm68060fprestore
1541#endif
1542	tstb	%a0@				| null state frame?
1543	jeq	Lm68881rdone			| yes, easy
1544	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi	| restore FP control registers
1545	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general registers
1546Lm68881rdone:
1547	frestore %a0@				| restore state
1548	rts
1549#endif
1550
1551#ifdef M68060
1552Lm68060fprestore:
1553	tstb	%a0@(2)				| null state frame?
1554	jeq	Lm68060fprdone			| yes, easy
1555	fmovem	%a0@(FPF_FPCR),%fpcr		| restore FP control registers
1556	fmovem	%a0@(FPF_FPSR),%fpsr
1557	fmovem	%a0@(FPF_FPI),%fpi
1558	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general registers
1559Lm68060fprdone:
1560	frestore %a0@				| restore state
1561	rts
1562#endif
1563#endif
1564
1565/*
1566 * Handle the nitty-gritty of rebooting the machine.
1567 *
1568 */
1569#if defined(P5PPC68KBOARD)
1570	.data
1571GLOBAL(p5ppc)
1572	.long	0
1573	.text
1574#endif
1575
1576ENTRY_NOPROFILE(doboot)
1577	movl	#CACHE_OFF,%d0
1578	cmpl	#MMU_68040,_C_LABEL(mmutype)	| is it 68040
1579	jne	Ldoboot0
1580	.word	0xf4f8			| cpusha bc - push and invalidate caches
1581	nop
1582	movl	#CACHE40_OFF,%d0
1583Ldoboot0:
1584	movc	%d0,%cacr			| disable on-chip cache(s)
1585
1586	movw	#0x2700,%sr			| cut off any interrupts
1587
1588#if defined(P5PPC68KBOARD)
1589	tstl	_C_LABEL(p5ppc)
1590	jne	Lp5ppcboot
1591#endif
1592#if defined(DRACO)
1593	cmpb	#0x7d,_C_LABEL(machineid)
1594	jeq	LdbOnDraCo
1595#endif
1596
1597	| clear first 4k of CHIPMEM
1598	movl	_C_LABEL(CHIPMEMADDR),%a0
1599	movl	%a0,%a1
1600	movl	#1024,%d0
1601Ldb1:
1602	clrl	%a0@+
1603	dbra	%d0,Ldb1
1604
1605	| now, copy the following code over
1606|	lea	%a1@(Ldoreboot),%a0	| KVA starts at 0, CHIPMEM is phys 0
1607|	lea	%a1@(Ldorebootend),%a1
1608|	lea	%pc@(Ldoreboot-.+2),%a0
1609|	addl	%a1,%a0
1610|	lea	%a0@(128),%a1
1611|	lea	%pc@(Ldoreboot-.+2),%a2
1612	lea	Ldoreboot,%a2
1613	lea	Ldorebootend,%a0
1614	addl	%a1,%a0
1615	addl	%a2,%a1
1616	exg	%a0,%a1
1617Ldb2:
1618	movel	%a2@+,%a0@+
1619	cmpl	%a1,%a0
1620	jle	Ldb2
1621
1622	| ok, turn off MMU..
1623Ldoreboot:
1624	cmpl	#MMU_68040,_C_LABEL(mmutype)	| is it 68040
1625 	jeq	Lmmuoff040
1626	lea	_ASM_LABEL(zero),%a0
1627	pmove	%a0@,%tc		| Turn off MMU
1628	lea	_ASM_LABEL(nullrp),%a0
1629	pmove	%a0@,%crp		| Turn off MMU some more
1630	pmove	%a0@,%srp		| Really, really, turn off MMU
1631	jra	Ldoboot1
1632Lmmuoff040:
1633	movl	#0,%d0
1634	.word	0x4e7b,0x0003		| movc d0,TC
1635	.word	0x4e7b,0x0806		| movc d0,URP
1636	.word	0x4e7b,0x0807		| movc d0,SRP
1637Ldoboot1:
1638
1639	| this weird code is the OFFICIAL way to reboot an Amiga ! ..
1640	lea	0x1000000,%a0
1641	subl	%a0@(-0x14),%a0
1642	movl	%a0@(4),%a0
1643	subl	#2,%a0
1644	cmpw	#0x4e70,%a0@		| 68040 kludge: if ROM entry is not
1645	jne	Ldoreset		| a reset, do the reset here
1646	jmp	%a0@			| otherwise, jump to the ROM to reset
1647	| reset needs to be on longword boundary
1648	nop
1649#ifdef __ELF__
1650	.align	4
1651#else
1652	.align	2
1653#endif
1654Ldoreset:
1655	| reset unconfigures all memory!
1656	reset
1657	| now rely on prefetch for next jmp
1658	jmp	%a0@
1659	| NOT REACHED
1660
1661#if defined(P5PPC68KBOARD)
1662Lp5ppcboot:
1663| The Linux-Apus boot code does it in a similar way
1664| For 040 on uncached pages, eieio can be replaced by nothing.
1665	movl	_C_LABEL(ZTWOROMADDR),%a0
1666	lea	%a0@(0xf60000-0xd80000),%a0
1667	movb	#0x60,%a0@(0x20)
1668	movb	#0x50,%a0@(0x20)
1669	movb	#0x30,%a0@(0x20)
1670	movb	#0x40,%a0@(0x18)
1671	movb	#0x04,%a0@
1672Lwaithere:
1673	jra	Lwaithere
1674#endif
1675
1676#ifdef DRACO
1677LdbOnDraCo:
1678| we use a TTR. We want to boot even if half of us is already dead.
1679
1680	movl	_C_LABEL(boot_fphystart), %d0
1681	lea	LdoDraCoBoot, %a0
1682	lea	%a0@(%d0),%a0
1683	andl	#0xFF000000,%d0
1684	orl	#0x0000C044,%d0	| enable, supervisor, CI, RO
1685	.word	0x4e7b,0x0004	| movc d0,ITT0
1686	jmp	%a0@
1687
1688#ifdef __ELF__
1689	.align	4
1690#else
1691	.align	2
1692#endif
1693LdoDraCoBoot:
1694| turn off MMU now ... were more ore less guaranteed to run on 040/060:
1695	movl	#0,%d0
1696	.word	0x4e7b,0x0003	| movc d0,TC
1697	.word	0x4e7b,0x0806	| movc d0,URP
1698	.word	0x4e7b,0x0807	| movc d0,SRP
1699	.word	0x4e7b,0x0004	| movc d0,ITT0
1700	nop
1701| map in boot ROM @0:
1702	reset
1703| and simulate what a reset exception would have done.
1704	movl	4,%a0
1705	movl	0,%a7
1706	jmp	%a0@
1707	| NOT REACHED
1708#endif
1709/*
1710 * Reboot directly into a new kernel image.
1711 * kernel_reload(image, image_size, entry,
1712 *		 fastram_start, fastram_size, chipram_start, esym, eclockfreq)
1713 */
1714ENTRY_NOPROFILE(kernel_reload)
1715	lea	Lreload_copy,%a0	| cursory validity check of new kernel
1716	movl	%a0@,%d0		|  to see if the kernel reload code
1717	addl	%sp@(4),%a0		|  in new image matches running kernel
1718	cmpl	%a0@,%d0
1719	jeq	Lreload_ok
1720	rts				| It doesn't match - can't reload
1721Lreload_ok:
1722	jsr	_C_LABEL(bootsync)
1723	CUSTOMADDR(%a5)
1724
1725	movew	#(1<<9),%a5@(0x096)	| disable DMA (before clobbering chipmem)
1726
1727	movl	#CACHE_OFF,%d0
1728	cmpl	#MMU_68040,_C_LABEL(mmutype)
1729	jne	Lreload1
1730	.word	0xf4f8		| cpusha bc - push and invalidate caches
1731	nop
1732	movl	#CACHE40_OFF,%d0
1733Lreload1:
1734	movc	%d0,%cacr		| disable on-chip cache(s)
1735
1736	movw	#0x2700,%sr		| cut off any interrupts
1737	movel	_C_LABEL(boothowto),%d7	| save boothowto
1738	movel	_C_LABEL(machineid),%d5	| (and machineid)
1739
1740	movel	%sp@(16),%a0		| load memory parameters
1741	movel	%sp@(20),%d0
1742	movel	%sp@(24),%d1
1743	movel	%sp@(28),%a4		| esym
1744	movel	%sp@(32),%d4		| eclockfreq
1745	movel	%sp@(36),%d3		| AGA mode
1746	movel	%sp@(40),%a2		| sync inhibit flags
1747	movel	%sp@(44),%d6		| boot partition offset
1748
1749	movel	%sp@(12),%a6		| find entrypoint (a6)
1750
1751	movel	%sp@(4),%a1		| copy kernel to low chip memory
1752	movel	%sp@(8),%d2
1753	movl	_C_LABEL(CHIPMEMADDR),%a3
1754Lreload_copy:
1755	movel	%a1@+,%a3@+
1756	subl	#4,%d2
1757	jcc	Lreload_copy
1758
1759	| ok, turn off MMU..
1760	cmpl	#MMU_68040,_C_LABEL(mmutype)
1761	jeq	Lreload040
1762	lea	_ASM_LABEL(zero),%a3
1763	pmove	%a3@,%tc		| Turn off MMU
1764	lea	_ASM_LABEL(nullrp),%a3
1765	pmove	%a3@,%crp		| Turn off MMU some more
1766	pmove	%a3@,%srp		| Really, really, turn off MMU
1767	jra	Lreload2
1768Lreload040:
1769	movl	#0,%d2
1770	.word	0x4e7b,0x2003	| movc d2,TC
1771	.word	0x4e7b,0x2806	| movc d2,URP
1772	.word	0x4e7b,0x2807	| movc d2,SRP
1773Lreload2:
1774
1775	moveq	#0,%d2			| clear unused registers
1776	subl	%a1,%a1
1777	subl	%a3,%a3
1778	subl	%a5,%a5
1779	jmp	%a6@			| start new kernel
1780
1781
1782| A do-nothing MMU root pointer (includes the following long as well)
1783
1784ASLOCAL(nullrp)
1785	.long	0x7fff0001
1786ASLOCAL(zero)
1787	.long	0
1788Ldorebootend:
1789
1790#ifdef __ELF__
1791	.align 4
1792#else
1793	.align 2
1794#endif
1795	nop
1796ENTRY_NOPROFILE(delay)
1797ENTRY_NOPROFILE(DELAY)
1798	movql #10,%d1		| 2 +2
1799	movl %sp@(4),%d0	| 4 +4
1800	lsll %d1,%d0		| 8 +2
1801	movl _C_LABEL(delaydivisor),%d1	| A +6
1802Ldelay:				| longword aligned again.
1803	subl %d1,%d0
1804	jcc Ldelay
1805	rts
1806
1807#ifdef M68060
1808ENTRY_NOPROFILE(intemu60)
1809	addql	#1,L60iem
1810	jra	_C_LABEL(I_CALL_TOP)+128+0x00
1811ENTRY_NOPROFILE(fpiemu60)
1812	addql	#1,L60fpiem
1813	jra	_C_LABEL(FP_CALL_TOP)+128+0x30
1814ENTRY_NOPROFILE(fpdemu60)
1815	addql	#1,L60fpdem
1816	jra	_C_LABEL(FP_CALL_TOP)+128+0x38
1817ENTRY_NOPROFILE(fpeaemu60)
1818	addql	#1,L60fpeaem
1819	jra	_C_LABEL(FP_CALL_TOP)+128+0x40
1820#endif
1821
1822	.data
1823	.space	NBPG
1824ASLOCAL(tmpstk)
1825
1826GLOBAL(mmutype)
1827	.long	MMU_68851
1828GLOBAL(cputype)
1829	.long	CPU_68020
1830GLOBAL(ectype)
1831	.long	EC_NONE
1832GLOBAL(fputype)
1833	.long	FPU_NONE
1834GLOBAL(protorp)
1835	.long	0x80000002,0	| prototype root pointer
1836
1837GLOBAL(proc0paddr)
1838	.long	0		| KVA of proc0 u-area
1839
1840GLOBAL(delaydivisor)
1841	.long	12		| should be enough for 80 MHz 68060
1842				| will be adapted to other CPUs in
1843				| start_c_cleanup and calibrated
1844				| at clock attach time.
1845#ifdef DEBUG
1846ASGLOBAL(fulltflush)
1847	.long	0
1848ASGLOBAL(fullcflush)
1849	.long	0
1850ASGLOBAL(timebomb)
1851	.long	0
1852#endif
1853/* interrupt counters */
1854GLOBAL(intrnames)
1855	.asciz	"spur"		| spurious interrupt
1856	.asciz	"tbe/soft"	| serial TBE & software
1857	.asciz	"kbd/ports"	| keyboard & PORTS
1858	.asciz	"vbl"		| vertical blank
1859	.asciz	"audio"		| audio channels
1860	.asciz	"rbf"		| serial receive
1861	.asciz	"exter"		| EXTERN
1862	.asciz	"nmi"		| non-maskable
1863	.asciz	"clock"		| clock interrupts
1864	.asciz	"spur6"		| spurious level 6
1865#ifdef DRACO
1866	.asciz	"kbd/soft"	| 1: native keyboard, soft ints
1867	.asciz	"cia/zbus"	| 2: cia, PORTS
1868	.asciz	"lclbus"	| 3: local bus, e.g. Altais vbl
1869	.asciz	"drscsi"	| 4: mainboard scsi
1870	.asciz	"superio"	| 5: superio chip
1871	.asciz	"lcl/zbus"	| 6: lcl/zorro lev6
1872	.asciz	"buserr"	| 7: nmi: bus timeout
1873#endif
1874#ifdef M68060
1875	.asciz	"60intemu"
1876	.asciz	"60fpiemu"
1877	.asciz	"60fpdemu"
1878	.asciz	"60fpeaemu"
1879	.asciz	"60bpe"
1880#endif
1881#ifdef FPU_EMULATE
1882	.asciz	"fpe"
1883#endif
1884GLOBAL(eintrnames)
1885#ifdef __ELF__
1886	.align	4
1887#else
1888	.align	2
1889#endif
1890GLOBAL(intrcnt)
1891	.long	0,0,0,0,0,0,0,0,0,0
1892#ifdef DRACO
1893ASLOCAL(Drintrcnt)
1894	.long	0,0,0,0,0,0,0
1895#endif
1896#ifdef M68060
1897L60iem:		.long	0
1898L60fpiem:	.long	0
1899L60fpdem:	.long	0
1900L60fpeaem:	.long	0
1901L60bpe:		.long	0
1902#endif
1903#ifdef FPU_EMULATE
1904Lfpecnt:	.long	0
1905#endif
1906GLOBAL(eintrcnt)
1907