xref: /netbsd-src/sys/arch/amiga/amiga/locore.s (revision 36f542a77b0de48a486f9f4c524ca47e469d17b5)
1/*	$NetBSD: locore.s,v 1.172 2024/01/19 18:18:53 thorpej 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. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: Utah $Hdr: locore.s 1.58 91/04/22$
37 *
38 *	@(#)locore.s	7.11 (Berkeley) 5/9/91
39 *
40 * Original (hp300) Author: unknown, maybe Mike Hibler?
41 * Amiga author: Markus Wild
42 * Other contributors: Bryan Ford (kernel reload stuff)
43 */
44
45#include "opt_fpu_emulate.h"
46#include "opt_bb060stupidrom.h"
47#include "opt_p5ppc68kboard.h"
48#include "opt_compat_netbsd.h"
49#include "opt_compat_sunos.h"
50#include "opt_fpsp.h"
51#include "opt_kgdb.h"
52#include "opt_lockdebug.h"
53#include "opt_lev6_defer.h"
54#include "opt_m68k_arch.h"
55
56#include "assym.h"
57#include <machine/asm.h>
58#include <machine/trap.h>
59
60	.text
61GLOBAL(kernel_text)
62L_base:
63	.long	0x4ef80400+PAGE_SIZE	/* jmp jmp0.w */
64	.fill	PAGE_SIZE/4-1,4,0/*xdeadbeef*/
65
66#include <amiga/amiga/vectors.s>
67#include <amiga/amiga/custom.h>
68
69#ifdef DRACO
70#include <amiga/amiga/drcustom.h>
71#endif
72
73#define CIAAADDR(ar)	movl	_C_LABEL(CIAAbase),ar
74#define CIABADDR(ar)	movl	_C_LABEL(CIABbase),ar
75#define CUSTOMADDR(ar)	movl	_C_LABEL(CUSTOMbase),ar
76#define INTREQRADDR(ar)	movl	_C_LABEL(INTREQRaddr),ar
77#define INTREQWADDR(ar)	movl	_C_LABEL(INTREQWaddr),ar
78#define INTENAWADDR(ar) movl	_C_LABEL(amiga_intena_write),ar
79#define	INTENARADDR(ar)	movl	_C_LABEL(amiga_intena_read),ar
80
81	.text
82/*
83 * This is where we wind up if the kernel jumps to location 0.
84 * (i.e. a bogus PC)  This is known to immediately follow the vector
85 * table and is hence at 0x400 (see reset vector in vectors.s).
86 */
87	pea	Ljmp0panic
88	jbsr	_C_LABEL(panic)
89	/* NOTREACHED */
90Ljmp0panic:
91	.asciz	"kernel jump to zero"
92	.even
93
94/*
95 * Do a dump.
96 * Called by auto-restart.
97 */
98ENTRY_NOPROFILE(doadump)
99	jbsr	_C_LABEL(dumpsys)
100	jbsr	_C_LABEL(doboot)
101	/*NOTREACHED*/
102
103/*
104 * Trap/interrupt vector routines
105 */
106#include <m68k/m68k/trap_subr.s>
107
108#if defined(M68040) || defined(M68060)
109ENTRY_NOPROFILE(addrerr4060)
110	clrl	%sp@-			| stack adjust count
111	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
112	movl	%usp,%a0		| save the user SP
113	movl	%a0,%sp@(FR_SP)		|   in the savearea
114	movl	%sp@(FR_HW+8),%sp@-
115	clrl	%sp@-			| dummy code
116	movl	#T_ADDRERR,%sp@-	| mark address error
117	jra	_ASM_LABEL(faultstkadj)	| and deal with it
118#endif
119
120#if defined(M68060)
121ENTRY_NOPROFILE(buserr60)
122	clrl	%sp@-			| stack adjust count
123	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
124	movl	%usp,%a0		| save the user SP
125	movl	%a0,%sp@(FR_SP)		|   in the savearea
126	movel	%sp@(FR_HW+12),%d0	| FSLW
127	btst	#2,%d0			| branch prediction error?
128	jeq	Lnobpe
129	movc	%cacr,%d2
130	orl	#IC60_CABC,%d2		| clear all branch cache entries
131	movc	%d2,%cacr
132	movl	%d0,%d1
133	addql	#1,L60bpe
134	andl	#0x7ffd,%d1
135	jeq	_ASM_LABEL(faultstkadjnotrap2)
136Lnobpe:
137| we need to adjust for misaligned addresses
138	movl	%sp@(FR_HW+8),%d1	| grab VA
139	btst	#27,%d0			| check for mis-aligned access
140	jeq	Lberr3			| no, skip
141	addl	#28,%d1			| yes, get into next page
142					| operand case: 3,
143					| instruction case: 4+12+12
144	andl	#PG_FRAME,%d1           | and truncate
145Lberr3:
146	movl	%d1,%sp@-
147	movl	%d0,%sp@-		| code is FSLW now.
148	andw	#0x1f80,%d0
149	jeq	Lisberr
150	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
151	jra	_ASM_LABEL(faultstkadj)	| and deal with it
152#endif
153#if defined(M68040)
154ENTRY_NOPROFILE(buserr40)
155	clrl	%sp@-			| stack adjust count
156	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
157	movl	%usp,%a0		| save the user SP
158	movl	%a0,%sp@(FR_SP)		|   in the savearea
159	movl	%sp@(FR_HW+20),%d1	| get fault address
160	moveq	#0,%d0
161	movw	%sp@(FR_HW+12),%d0	| get SSW
162	btst	#11,%d0			| check for mis-aligned
163	jeq	Lbe1stpg		| no skip
164	addl	#3,%d1			| get into next page
165	andl	#PG_FRAME,%d1		| and truncate
166Lbe1stpg:
167	movl	%d1,%sp@-		| pass fault address.
168	movl	%d0,%sp@-		| pass SSW as code
169	btst	#10,%d0			| test ATC
170	jeq	Lisberr			| it is a bus error
171	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
172	jra	_ASM_LABEL(faultstkadj)	| and deal with it
173#endif
174
175ENTRY_NOPROFILE(buserr)
176ENTRY_NOPROFILE(addrerr)
177#if !(defined(M68020) || defined(M68030))
178	jra	_C_LABEL(badtrap)
179#else
180	clrl	%sp@-			| stack adjust count
181	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
182	movl	%usp,%a0		| save the user SP
183	movl	%a0,%sp@(FR_SP)		|   in the savearea
184	moveq	#0,%d0
185	movw	%sp@(FR_HW+10),%d0	| grab SSW for fault processing
186	btst	#12,%d0			| RB set?
187	jeq	LbeX0			| no, test RC
188	bset	#14,%d0			| yes, must set FB
189	movw	%d0,%sp@(FR_HW+10)	| for hardware too
190LbeX0:
191	btst	#13,%d0			| RC set?
192	jeq	LbeX1			| no, skip
193	bset	#15,%d0			| yes, must set FC
194	movw	%d0,%sp@(FR_HW+10)	| for hardware too
195LbeX1:
196	btst	#8,%d0			| data fault?
197	jeq	Lbe0			| no, check for hard cases
198	movl	%sp@(FR_HW+16),%d1	| fault address is as given in frame
199	jra	Lbe10			| thats it
200Lbe0:
201	btst	#4,%sp@(FR_HW+6)	| long (type B) stack frame?
202	jne	Lbe4			| yes, go handle
203	movl	%sp@(FR_HW+2),%d1	| no, can use save PC
204	btst	#14,%d0			| FB set?
205	jeq	Lbe3			| no, try FC
206	addql	#4,%d1			| yes, adjust address
207	jra	Lbe10			| done
208Lbe3:
209	btst	#15,%d0			| FC set?
210	jeq	Lbe10			| no, done
211	addql	#2,%d1			| yes, adjust address
212	jra	Lbe10			| done
213Lbe4:
214	movl	%sp@(FR_HW+36),%d1	| long format, use stage B address
215	btst	#15,%d0			| FC set?
216	jeq	Lbe10			| no, all done
217	subql	#2,%d1			| yes, adjust address
218Lbe10:
219	movl	%d1,%sp@-		| push fault VA
220	movl	%d0,%sp@-		| and padded SSW
221	movw	%sp@(FR_HW+8+6),%d0	| get frame format/vector offset
222	andw	#0x0FFF,%d0		| clear out frame format
223	cmpw	#12,%d0			| address error vector?
224	jeq	Lisaerr			| yes, go to it
225	movl	%d1,%a0			| fault address
226	movl	%sp@,%d0		| function code from ssw
227	btst	#8,%d0			| data fault?
228	jne	Lbe10a
229	movql	#1,%d0			| user program access FC
230					| (we dont separate data/program)
231	btst	#5,%sp@(FR_HW+8)	| supervisor mode?
232	jeq	Lbe10a			| if no, done
233	movql	#5,%d0			| else supervisor program access
234Lbe10a:
235	ptestr	%d0,%a0@,#7		| do a table search
236	pmove	%psr,%sp@		| save result
237	movb	%sp@,%d1
238	btst	#2,%d1			| invalid (incl. limit viol. and berr)?
239	jeq	Lmightnotbemerr		| no -> wp check
240	btst	#7,%d1			| is it MMU table berr?
241	jeq	Lismerr			| no, must be fast
242	jra	Lisberr1		| real bus err needs not be fast.
243Lmightnotbemerr:
244	btst	#3,%d1			| write protect bit set?
245	jeq	Lisberr1		| no: must be bus error
246	movl	%sp@,%d0		| ssw into low word of d0
247	andw	#0xc0,%d0		| Write protect is set on page:
248	cmpw	#0x40,%d0		| was it read cycle?
249	jeq	Lisberr1		| yes, was not WPE, must be bus err
250Lismerr:
251	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
252	jra	_ASM_LABEL(faultstkadj)	| and deal with it
253Lisaerr:
254	movl	#T_ADDRERR,%sp@-	| mark address error
255	jra	_ASM_LABEL(faultstkadj)	| and deal with it
256Lisberr1:
257	clrw	%sp@			| re-clear pad word
258#endif
259Lisberr:				| also used by M68040/60
260	tstl	_C_LABEL(nofault)	| device probe?
261	jeq	LberrIsProbe		| no, handle as usual
262	movl	_C_LABEL(nofault),%sp@-	| yes,
263	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
264	/* NOTREACHED */
265LberrIsProbe:
266	movl	#T_BUSERR,%sp@-		| mark bus error
267	jra	_ASM_LABEL(faultstkadj)	| and deal with it
268
269/*
270 * FP exceptions.
271 */
272ENTRY_NOPROFILE(fpfline)
273#if defined(M68040)
274	cmpw	#0x202c,%sp@(6)		| format type 2?
275	jne	_C_LABEL(illinst)	| no, not an FP emulation
276#ifdef FPSP
277	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
278#endif
279#endif
280
281#ifdef FPU_EMULATE
282ENTRY_NOPROFILE(fpemuli)
283	addql	#1,Lfpecnt
284	clrl	%sp@-			| stack adjust count
285	moveml	%d0-%d7/%a0-%a7,%sp@-	| save registers
286	movql	#T_FPEMULI,%d0		| denote as FP emulation trap
287	jra	_ASM_LABEL(fault)	| do it
288#endif
289
290ENTRY_NOPROFILE(fpunsupp)
291#if defined(M68040)
292	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
293	jne	_C_LABEL(illinst)	| no, treat as illinst
294#ifdef FPSP
295	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
296#else
297	clrl	%sp@-			| stack adjust count
298	moveml	%d0-%d7/%a0-%a7,%sp@-	| save registers
299	movql	#T_FPEMULD,%d0		| denote as FP emulation trap
300	jra	_ASM_LABEL(fault)	| do it
301#endif
302#else
303	jra	_C_LABEL(illinst)
304#endif
305/*
306 * Handles all other FP coprocessor exceptions.
307 * Note that since some FP exceptions generate mid-instruction frames
308 * and may cause signal delivery, we need to test for stack adjustment
309 * after the trap call.
310 */
311ENTRY_NOPROFILE(fpfault)
312#ifdef FPCOPROC
313	clrl	%sp@-			| stack adjust count
314	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
315	movl	%usp,%a0		| and save
316	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
317	clrl	%sp@-			| no VA arg
318	movl	_C_LABEL(curpcb),%a0	| current pcb
319	lea	%a0@(PCB_FPCTX),%a0	| address of FP savearea
320	fsave	%a0@			| save state
321#if defined(M68020) || defined(M68030)
322#if defined(M68060) || defined(M68040)
323	movb	_C_LABEL(machineid)+3,%d0
324	andb	#0x90,%d0		| AMIGA_68060 | AMIGA_68040
325	jne	Lfptnull		| XXX
326#endif
327	tstb	%a0@			| null state frame?
328	jeq	Lfptnull		| yes, safe
329	clrw	%d0			| no, need to tweak BIU
330	movb	%a0@(1),%d0		| get frame size
331	bset	#3,%a0@(0,%d0:w)	| set exc_pend bit of BIU
332Lfptnull:
333#endif
334	fmovem	%fpsr,%sp@-		| push fpsr as code argument
335	frestore %a0@			| restore state
336	movl	#T_FPERR,%sp@-		| push type arg
337	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
338#else
339	jra	_C_LABEL(badtrap)	| treat as an unexpected trap
340#endif
341
342/*
343 * Other exceptions only cause four and six word stack frame and require
344 * no post-trap stack adjustment.
345 */
346
347ENTRY_NOPROFILE(badtrap)
348	INTERRUPT_SAVEREG
349	movw	%sp@(22),%sp@-		| push exception vector info
350	clrw	%sp@-
351	movl	%sp@(22),%sp@-		| and PC
352	jbsr	_C_LABEL(straytrap)	| report
353	addql	#8,%sp			| pop args
354	INTERRUPT_RESTOREREG		| restore regs
355	jra	_ASM_LABEL(rei)		| all done
356
357ENTRY_NOPROFILE(trap0)
358	clrl	%sp@-			| stack adjust count
359	moveml	%d0-%d7/%a0-%a7,%sp@-	| save user registers
360	movl	%usp,%a0		| save the user SP
361	movl	%a0,%sp@(FR_SP)		|   in the savearea
362	movl	%d0,%sp@-		| push syscall number
363	jbsr	_C_LABEL(syscall)	| handle it
364	addql	#4,%sp			| pop syscall arg
365	movl	%sp@(FR_SP),%a0		| grab and restore
366	movl	%a0,%usp		|   user SP
367	moveml	%sp@+,%d0-%d7/%a0-%a6	| restore most registers
368	addql	#8,%sp			| pop SP and stack adjust
369	jra	_ASM_LABEL(rei)		| all done
370
371/*
372 * Trap 12 is the entry point for the cachectl "syscall"
373 *	cachectl(command, addr, length)
374 * command in d0, addr in a1, length in d1
375 */
376ENTRY_NOPROFILE(trap12)
377	movl	_C_LABEL(curlwp),%a0
378	movl	%a0@(L_PROC),%sp@-	| push current proc pointer
379	movl	%d1,%sp@-		| push length
380	movl	%a1,%sp@-		| push addr
381	movl	%d0,%sp@-		| push command
382	jbsr	_C_LABEL(cachectl1)	| do it
383	lea	%sp@(16),%sp		| pop args
384	jra	_ASM_LABEL(rei)		| all done
385
386/*
387 * Trap 15 is used for:
388 *	- KGDB traps
389 *	- trace traps for SUN binaries (not fully supported yet)
390 * We just pass it on and let trap() sort it all out
391 */
392ENTRY_NOPROFILE(trap15)
393	clrl	%sp@-
394	moveml	%d0-%d7/%a0-%a7,%sp@-
395#ifdef KGDB
396	moveq	#T_TRAP15,%d0
397	movw	%sp@(FR_HW),%d1		| get PSW
398	andw	#PSL_S,%d1		| from user mode?
399	jeq	_ASM_LABEL(fault)	| yes, just a regular fault
400	movl	%d0,%sp@-
401	jbsr	_C_LABEL(kgdb_trap_glue) | returns if no debugger
402	addl	#4,%sp
403#endif
404	moveq	#T_TRAP15,%d0
405	jra	_ASM_LABEL(fault)
406
407/*
408 * Hit a breakpoint (trap 1 or 2) instruction.
409 * Push the code and treat as a normal fault.
410 */
411ENTRY_NOPROFILE(trace)
412	clrl	%sp@-
413	moveml	%d0-%d7/%a0-%a7,%sp@-
414#ifdef KGDB
415	moveq	#T_TRACE,%d0
416	movw	%sp@(FR_HW),%d1		| get SSW
417	andw	#PSL_S,%d1		| from user mode?
418	jeq	_ASM_LABEL(fault)	| no, regular fault
419	movl	%d0,%sp@-
420	jbsr	_C_LABEL(kgdb_trap_glue) | returns if no debugger
421	addl	#4,%sp
422#endif
423	moveq	#T_TRACE,%d0
424	jra	_ASM_LABEL(fault)
425
426/*
427 * Interrupt handlers.
428 *
429 *	Level 0:	Spurious: ignored.
430 *	Level 1:	builtin-RS232 TBE, softint (not used yet)
431 *	Level 2:	keyboard (CIA-A) + DMA + SCSI
432 *	Level 3:	VBL
433 *	Level 4:	not used
434 *	Level 5:	builtin-RS232 RBF
435 *	Level 6:	Clock (CIA-B-Timers), Floppy index pulse
436 *	Level 7:	Non-maskable: shouldn't be possible. ignore.
437 */
438
439/* Provide a generic interrupt dispatcher, only handle hardclock (int6)
440 * and serial RBF (int5) specially, to improve performance
441 */
442ENTRY_NOPROFILE(spurintr)
443	addql	#1,_C_LABEL(intr_depth)
444	addql	#1,_C_LABEL(intrcnt)+0
445	INTERRUPT_SAVEREG
446	CPUINFO_INCREMENT(CI_NINTR)
447	INTERRUPT_RESTOREREG
448	subql	#1,_C_LABEL(intr_depth)
449	jra	_ASM_LABEL(rei)
450
451ENTRY_NOPROFILE(lev5intr)
452	addql	#1,_C_LABEL(intr_depth)
453	INTERRUPT_SAVEREG
454#include "ser.h"
455#if NSER > 0
456	jsr	_C_LABEL(ser_fastint)
457#else
458	INTREQWADDR(%a0)
459	movew	#INTF_RBF,%a0@		| clear RBF interrupt in intreq
460#endif
461	CPUINFO_INCREMENT(CI_NINTR)
462	INTERRUPT_RESTOREREG
463	addql	#1,_C_LABEL(intrcnt)+20
464	subql	#1,_C_LABEL(intr_depth)
465	jra	_ASM_LABEL(rei)
466
467#ifdef DRACO
468ENTRY_NOPROFILE(DraCoLev2intr)
469	addql	#1,_C_LABEL(intr_depth)
470	INTERRUPT_SAVEREG
471
472	CIAAADDR(%a0)
473	movb	%a0@(CIAICR),%d0	| read irc register (clears ints!)
474	jge     Ldrintrcommon		| CIAA IR not set, go through isr chain
475	movel	_C_LABEL(draco_intpen),%a0
476|	andib	#4,%a0@
477|XXX this would better be
478	bclr	#2,%a0@
479	btst	#0,%d0			| timerA interrupt?
480	jeq	Ldraciaend
481
482	movl	%sp,%sp@-		| push pointer to clockframe
483	movw	#PSL_HIGHIPL,%sr	| hardclock at high IPL
484	jbsr	_C_LABEL(hardclock)	| call generic clock int routine
485	addql	#4,%sp			| pop params
486	addql	#1,_C_LABEL(intrcnt)+32	| add another system clock interrupt
487
488Ldraciaend:
489	CPUINFO_INCREMENT(CI_NINTR)
490	INTERRUPT_RESTOREREG
491	subql	#1,_C_LABEL(intr_depth)
492	jra	_ASM_LABEL(rei)
493
494/* XXX on the DraCo rev. 4 or later, lev 1 is vectored here. */
495ENTRY_NOPROFILE(DraCoLev1intr)
496	addql	#1,_C_LABEL(intr_depth)
497	INTERRUPT_SAVEREG
498	movl	_C_LABEL(draco_ioct),%a0
499	btst	#5,%a0@(7)
500	jeq	Ldrintrcommon
501	btst	#4,%a0@(7)	| this only happens during autoconfiguration,
502	jeq	Ldrintrcommon	| so test last.
503	movw	#PSL_HIGHIPL,%sr	| run clock at high ipl
504Ldrclockretry:
505	movl	%sp,%sp@-		| push pointer to clockframe
506	jbsr	_C_LABEL(hardclock)
507	addql	#4,%sp			| pop params
508	addql	#1,_C_LABEL(intrcnt)+32	| add another system clock interrupt
509
510	movl	_C_LABEL(draco_ioct),%a0
511	tstb	%a0@(9)		| latch timer value
512	movw	%a0@(11),%d0	| can't use movpw here, might be 68060
513	movb	%a0@(13),%d0
514	addw	_C_LABEL(amiga_clk_interval)+2,%d0
515	movb	%d0,%a0@(13)	| low byte: latch write value
516	movw	%d0,%a0@(11)	| ...and write it into timer
517	tstw	%d0		| already positive?
518	jcs	Ldrclockretry	| we lost more than one tick, call us again.
519
520	clrb	%a0@(9)		| reset timer irq
521
522	CPUINFO_INCREMENT(CI_NINTR)
523	INTERRUPT_RESTOREREG
524	subql	#1,_C_LABEL(intr_depth)
525	jra	_ASM_LABEL(rei)	| XXXX: shouldn't we call the normal lev1?
526
527/* XXX on the DraCo, lev 1, 3, 4, 5 and 6 are vectored here by initcpu() */
528ENTRY_NOPROFILE(DraCoIntr)
529	addql	#1,_C_LABEL(intr_depth)
530	INTERRUPT_SAVEREG
531Ldrintrcommon:
532	lea	_ASM_LABEL(Drintrcnt)-4,%a0
533	movw	%sp@(22),%d0		| use vector offset
534	andw	#0xfff,%d0		|   sans frame type
535	addql	#1,%a0@(-0x60,%d0:w)	|     to increment apropos counter
536	movw	%sr,%sp@-		| push current SR value
537	clrw	%sp@-			|    padded to longword
538	jbsr	_C_LABEL(intrhand)	| handle interrupt
539	addql	#4,%sp			| pop SR
540	CPUINFO_INCREMENT(CI_NINTR)
541	INTERRUPT_RESTOREREG
542	subql	#1,_C_LABEL(intr_depth)
543	jra	_ASM_LABEL(rei)
544#endif
545
546
547ENTRY_NOPROFILE(lev1intr)
548ENTRY_NOPROFILE(lev2intr)
549ENTRY_NOPROFILE(lev3intr)
550#ifndef LEV6_DEFER
551ENTRY_NOPROFILE(lev4intr)
552#endif
553	addql	#1,_C_LABEL(intr_depth)
554	INTERRUPT_SAVEREG
555Lintrcommon:
556	lea	_C_LABEL(intrcnt),%a0
557	movw	%sp@(22),%d0		| use vector offset
558	andw	#0xfff,%d0		|   sans frame type
559	addql	#1,%a0@(-0x60,%d0:w)	|     to increment apropos counter
560	movw	%sr,%sp@-		| push current SR value
561	clrw	%sp@-			|    padded to longword
562	jbsr	_C_LABEL(intrhand)	| handle interrupt
563	addql	#4,%sp			| pop SR
564	CPUINFO_INCREMENT(CI_NINTR)
565	INTERRUPT_RESTOREREG
566	subql	#1,_C_LABEL(intr_depth)
567	jra	_ASM_LABEL(rei)
568
569/* XXX used to be ifndef DRACO; vector will be overwritten by initcpu() */
570
571ENTRY_NOPROFILE(lev6intr)
572#ifdef LEV6_DEFER
573	/*
574	 * cause a level 4 interrupt (AUD3) to occur as soon
575	 * as we return. Block generation of level 6 ints until
576	 * we have dealt with this one.
577	 */
578	addql	#1,_C_LABEL(intr_depth)
579	moveml	%d0/%a0,%sp@-
580	INTREQRADDR(%a0)
581	movew	%a0@,%d0
582	btst	#INTB_EXTER,%d0
583	jeq	Llev6spur
584	INTREQWADDR(%a0)
585	movew	#INTF_SETCLR+INTF_AUD3,%a0@
586	INTENAWADDR(%a0)
587	movew	#INTF_EXTER,%a0@
588	movew	#INTF_SETCLR+INTF_AUD3,%a0@	| make sure THIS one is ok...
589	moveml	%sp@+,%d0/%a0
590	subql	#1,_C_LABEL(intr_depth)
591	rte
592Llev6spur:
593	addql	#1,_C_LABEL(intrcnt)+36	| count spurious level 6 interrupts
594	moveml	%sp@+,%d0/%a0
595	subql	#1,_C_LABEL(intr_depth)
596	rte
597
598ENTRY_NOPROFILE(lev4intr)
599ENTRY_NOPROFILE(fake_lev6intr)
600#endif
601	addql	#1,_C_LABEL(intr_depth)
602	INTERRUPT_SAVEREG
603#ifdef LEV6_DEFER
604	/*
605	 * check for fake level 6
606	 */
607	INTREQRADDR(%a0)
608	movew	%a0@,%d0
609	btst	#INTB_EXTER,%d0
610	jeq	Lintrcommon		| if EXTER not pending, handle normally
611#endif
612
613	CIABADDR(%a0)
614	movb	%a0@(CIAICR),%d0	| read irc register (clears ints!)
615	jge	Lchkexter		| CIAB IR not set, go through isr chain
616	INTREQWADDR(%a0)
617#ifndef LEV6_DEFER
618	movew	#INTF_EXTER,%a0@	| clear EXTER interrupt in intreq
619#else
620	movew	#INTF_EXTER+INTF_AUD3,%a0@ | clear EXTER & AUD3 in intreq
621	INTENAWADDR(%a0)
622	movew	#INTF_SETCLR+INTF_EXTER,%a0@ | reenable EXTER interrupts
623#endif
624	btst	#0,%d0			| timerA interrupt?
625	jeq     Ltstciab4		| no
626	movl	%d0,%sp@-		| push CIAB interrupt flags
627	lea	%sp@(4),%a1		| get pointer to clockframe
628	movl	%a1,%sp@-		| push pointer to clockframe
629	jbsr	_C_LABEL(hardclock)	| call generic clock int routine
630	addql	#4,%sp			| pop params
631	addql	#1,_C_LABEL(intrcnt)+32	| add another system clock interrupt
632	movl	%sp@+,%d0		| pop interrupt flags
633Ltstciab4:
634#include "fd.h"
635#if NFD > 0
636	btst	#4,%d0			| FLG (dskindex) interrupt?
637	jeq	Lskipciab		| no
638	jbsr	_C_LABEL(fdidxintr)	| tell floppy driver we got it
639Lskipciab:
640#endif
641| other ciab interrupts?
642Llev6done:
643	CPUINFO_INCREMENT(CI_NINTR)
644	INTERRUPT_RESTOREREG
645	subql	#1,_C_LABEL(intr_depth)
646	jra	_ASM_LABEL(rei)		| all done [can we do rte here?]
647Lchkexter:
648| check to see if EXTER request is really set?
649	movl	_C_LABEL(isr_exter),%a0	| get head of EXTER isr chain
650Lnxtexter:
651	movl	%a0,%d0			| test if any more entries
652	jeq	Lexterdone		| (spurious interrupt?)
653	movl	%a0,%sp@-		| save isr pointer
654	movl	%a0@(ISR_ARG),%sp@-
655	movl	%a0@(ISR_INTR),%a0
656	jsr	%a0@			| call isr handler
657	addql	#4,%sp
658	movl	%sp@+,%a0		| restore isr pointer
659	movl	%a0@(ISR_FORW),%a0	| get next pointer
660	tstl	%d0			| did handler process the int?
661	jeq	Lnxtexter		| no, try next
662Lexterdone:
663	INTREQWADDR(%a0)
664#ifndef LEV6_DEFER
665	movew	#INTF_EXTER,%a0@	| clear EXTER interrupt
666#else
667	movew	#INTF_EXTER+INTF_AUD3,%a0@ | clear EXTER & AUD3 interrupt
668	INTENAWADDR(%a0)
669	movew	#INTF_SETCLR+INTF_EXTER,%a0@ | reenable EXTER interrupts
670#endif
671	addql	#1,_C_LABEL(intrcnt)+24	| count EXTER interrupts
672	jra	Llev6done
673/* XXX endifndef DRACO used to be here */
674
675ENTRY_NOPROFILE(lev7intr)
676	addql	#1,_C_LABEL(intrcnt)+28
677	/*
678	 * some amiga zorro2 boards seem to generate spurious NMIs. Best
679	 * thing to do is to return as quick as possible. That's the
680	 * reason why I do RTE here instead of jra rei.
681	 */
682	rte				| all done
683
684
685/*
686 * Emulation of VAX REI instruction.
687 *
688 * This code deals with checking for and servicing ASTs
689 * (profiling, scheduling) and software interrupts (network, softclock).
690 * We check for ASTs first, just like the VAX.  To avoid excess overhead
691 * the T_ASTFLT handling code will also check for software interrupts so we
692 * do not have to do it here.  After identifying that we need an AST we
693 * drop the IPL to allow device interrupts.
694 *
695 * This code is complicated by the fact that sendsig may have been called
696 * necessitating a stack cleanup.  A cleanup should only be needed at this
697 * point for coprocessor mid-instruction frames (type 9), but we also test
698 * for bus error frames (type 10 and 11).
699 */
700ASENTRY_NOPROFILE(rei)
701#ifdef DEBUG
702	tstl	_C_LABEL(panicstr)	| have we panicked?
703	jne	Ldorte			| yes, do not make matters worse
704#endif
705	tstl	_C_LABEL(astpending)	| AST pending?
706	jeq	Ldorte			| no, done
707Lrei1:
708	btst	#5,%sp@			| yes, are we returning to user mode?
709	jne	Ldorte			| no, done
710	movw	#PSL_LOWIPL,%sr		| lower SPL
711	clrl	%sp@-			| stack adjust
712	moveml	%d0-%d7/%a0-%a7,%sp@-	| save all registers
713	movl	%usp,%a1		| including
714	movl	%a1,%sp@(FR_SP)		|    the users SP
715	clrl	%sp@-			| VA == none
716	clrl	%sp@-			| code == none
717	movl	#T_ASTFLT,%sp@-		| type == async system trap
718	pea	%sp@(12)		| fp == address of trap frame
719	jbsr	_C_LABEL(trap)		| go handle it
720	lea	%sp@(16),%sp		| pop value args
721	movl	%sp@(FR_SP),%a0		| restore user SP
722	movl	%a0,%usp		|   from save area
723	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
724	jne	Laststkadj		| yes, go to it
725	moveml	%sp@+,%d0-%d7/%a0-%a6	| no, restore most user regs
726	addql	#8,%sp			| toss SP and stack adjust
727	rte				| and do real RTE
728Laststkadj:
729	lea	%sp@(FR_HW),%a1		| pointer to HW frame
730	addql	#8,%a1			| source pointer
731	movl	%a1,%a0			| source
732	addw	%d0,%a0			|  + hole size = dest pointer
733	movl	%a1@-,%a0@-		| copy
734	movl	%a1@-,%a0@-		|  8 bytes
735	movl	%a0,%sp@(FR_SP)		| new SSP
736	moveml	%sp@+,%d0-%d7/%a0-%a6	| restore user registers
737	movl	%sp@,%sp		| and our SP
738Ldorte:
739	rte				| real return
740
741/*
742 * Kernel access to the current processes kernel stack is via a fixed
743 * virtual address.  It is at the same address as in the users VA space.
744 */
745BSS(esym,4)
746
747
748/*
749 * Initialization
750 *
751 * A5 contains physical load point from boot
752 * exceptions vector thru our table, that's bad.. just hope nothing exceptional
753 * happens till we had time to initialize ourselves..
754 */
755BSS(lowram,4)
756
757#define	RELOC(var, ar)			\
758	lea	_C_LABEL(var),ar;	\
759	addl	%a5,ar
760
761#define	ASRELOC(var, ar)		\
762	lea	_ASM_LABEL(var),ar;	\
763	addl	%a5,ar
764
765	.text
766
767	| XXX should be a symbol?
768	| 2: needs a4 = esym
769	| 3: no chipmem requirement
770	|    bootinfo data structure
771
772	.word	0
773	.word	0x0003			| loadbsd version required
774ASENTRY_NOPROFILE(start)
775	lea	%pc@(L_base),%a5	| initialize relocation register
776
777	movw	#PSL_HIGHIPL,%sr	| no interrupts
778	ASRELOC(tmpstk,%a6)
779	movl	%a6,%sp			| give ourselves a temporary stack
780
781	| save the passed parameters. "prepass" them on the stack for
782	| later catch by start_c()
783	movl	%a5,%sp@-		| pass loadbase
784	movl	%d6,%sp@-		| pass boot partition offset
785	movl	%a2,%sp@-		| pass sync inhibit flags
786	movl	%d3,%sp@-		| pass AGA mode
787	movl	%a4,%sp@-		| pass address of _esym
788	movl	%d1,%sp@-		| pass chipmem-size
789	movl	%d0,%sp@-		| pass fastmem-size
790	movl	%a0,%sp@-		| pass fastmem_start
791	movl	%d5,%sp@-		| pass machine id
792
793	/*
794	 * initialize some hw addresses to their physical address
795	 * for early running
796	 */
797#ifdef DRACO
798	/*
799	 * this is already dynamically done on DraCo
800	 */
801	cmpb	#0x7D,%sp@
802	jne	LisAmiga1
803| debug code:
804| we should need about 1 uSec for the loop.
805| we dont need the AGA mode register.
806	movel	#100000,%d3
807LisDraco0:
808#ifdef DEBUG_KERNEL_START
809	movb	#0,0x200003c8
810	movb	#00,0x200003c9
811	movb	#40,0x200003c9
812	movb	#00,0x200003c9
813|XXX:
814	movb	#0,0x200003c8
815	movb	#40,0x200003c9
816	movb	#00,0x200003c9
817	movb	#00,0x200003c9
818	subql	#1,%d3
819	jcc	LisDraco0
820#endif
821
822	RELOC(chipmem_start, %a0)
823	movl	#0,%a0@
824
825	RELOC(CIAAbase, %a0)
826	movl	#0x2801001, %a0@
827	RELOC(CIABbase, %a0)
828	movl	#0x2800000, %a0@
829
830	/* XXXX more to come here; as we need it */
831
832	jra	LisDraco1
833LisAmiga1:
834#endif
835	RELOC(chipmem_start, %a0)
836	movl	#0x400,%a0@
837	RELOC(CIAAbase, %a0)
838	movl	#0xbfe001,%a0@
839	RELOC(CIABbase, %a0)
840	movl	#0xbfd000,%a0@
841	RELOC(CUSTOMbase, %a0)
842	movl	#0xdff000,%a0@
843
844#ifdef DRACO
845LisDraco1:
846#endif
847	/*
848	 * initialize the timer frequency
849	 */
850	RELOC(eclockfreq, %a0)
851	movl	%d4,%a0@
852
853	movl	#AMIGA_68030,%d1	| 68030 Attn flag from exec
854	andl	%d5,%d1
855	jeq	Ltestfor020
856	RELOC(mmutype, %a0)
857	movl	#MMU_68030,%a0@		| assume 020 means 851
858	RELOC(cputype, %a0)
859	movl	#CPU_68030,%a0@
860	jra	Lsetcpu040		| skip to init.
861Ltestfor020:
862	movl	#AMIGA_68020,%d1	| 68020 Attn flag from exec
863	andl	%d5,%d1
864	jeq	Lsetcpu040
865	RELOC(mmutype, %a0)
866	movl	#MMU_68851,%a0@
867	RELOC(cputype, %a0)
868	movl	#CPU_68020,%a0@
869Lsetcpu040:
870	movl	#CACHE_OFF,%d0		| 68020/030 cache
871	movl	#AMIGA_68040,%d1
872	andl	%d1,%d5
873	jeq	Lstartnot040		| it is not 68040
874	RELOC(mmutype, %a0)
875	movl	#MMU_68040,%a0@		| same as hp300 for compat
876	RELOC(cputype, %a0)
877	movl	#CPU_68040,%a0@
878	.word	0xf4f8			| cpusha bc - push and invalidate caches
879	movl	#CACHE40_OFF,%d0	| 68040 cache disable
880#ifndef BB060STUPIDROM
881	btst	#7,%sp@(3)
882	jeq	Lstartnot040
883	movl	#CPU_68060,%a0@		| and in the cputype
884	orl	#IC60_CABC,%d0		| XXX and clear all 060 branch cache
885#else
886	movc	%d0,%cacr
887	bset	#30,%d0			| not allocate data cache bit
888	movc	%d0,%cacr		| does it stick?
889	movc	%cacr,%d0
890	tstl	%d0
891	jeq	Lstartnot040
892	bset	#7,%sp@(3)		| note it is '60 family in machineid
893	movl	#CPU_68060,%a0@		| and in the cputype
894	orl	#IC60_CABC,%d0		| XXX and clear all 060 branch cache
895	.word	0x4e7a,0x1808		| movc	pcr,d1
896	swap	%d1
897	cmpw	#0x430,%d1
898	jne	Lstartnot040		| but no FPU
899	bset	#6,%sp@(3)		| yes, we have FPU, note that
900	swap	%d1
901	bclr	#1,%d1			| ... and switch it on.
902	.word	0x4e7b,0x1808		| movc	d1,pcr
903#endif
904Lstartnot040:
905	movc	%d0,%cacr		| clear and disable on-chip cache(s)
906	movl	#_C_LABEL(vectab),%a0
907	movc	%a0,%vbr
908
909/* initialize source/destination control registers for movs */
910	moveq	#FC_USERD,%d0		| user space
911	movc	%d0,%sfc		|   as source
912	movc	%d0,%dfc		|   and destination of transfers
913
914/* let the C function initialize everything */
915	RELOC(start_c, %a0)
916	jbsr	%a0@
917	lea	%sp@(4*9),%sp
918
919#ifdef DRACO
920	RELOC(machineid,%a0)
921	cmpb	#0x7d,%a0@
922	jne	LAmiga_enable_MMU
923
924	lea	%pc@(0),%a0
925	movl	%a0,%d0
926	andl	#0xff000000,%d0
927	orl	#0x0000c044,%d0		| 16 MB, ro, cache inhibited
928	.word	0x4e7b,0x0004		| movc %d0,%itt0
929	.word	0xf518			| pflusha
930	movl	#MMU40_TCR_BITS,%d0	| enable MMU
931	.word	0x4e7b,0x0003		| movc %d0,%tc
932	jmp	Lcleanitt0:l
933Lcleanitt0:
934	movq	#0,%d0
935	.word	0x4e7b,0x0004		| movc %d0,%itt0
936	bra	LMMUenable_end
937
938LAmiga_enable_MMU:
939#endif /* DRACO */
940
941/* Copy just the code to enable the MMU into chip memory */
942	lea	LMMUenable_start,%a0
943	movl	#LMMUenable_start:l,%a1
944	lea	LMMUenable_end,%a2
945Lcopy_MMU_enabler:
946	movl	%a0@+,%a1@+
947	cmpl	%a0,%a2
948	jgt	Lcopy_MMU_enabler
949
950	jmp	LMMUenable_start:l
951
952LMMUenable_start:
953
954/* enable the MMU */
955#if defined(M68040) || defined(M68060)
956	RELOC(mmutype, %a0)
957	cmpl	#MMU_68040,%a0@
958	jne	Lenable030
959	.word	0xf518			| pflusha
960	movl	#MMU40_TCR_BITS,%d0	| enable MMU
961	.word	0x4e7b,0x0003		| movc	%d0,%tc
962	jmp	LMMUenable_end:l
963#endif /* M68040 || M68060 */
964Lenable030:
965	pflusha
966	lea	Ltc,%a0
967	pmove	%a0@,%tc
968	jmp	LMMUenable_end:l
969
970Ltc:	.long	MMU51_TCR_BITS		| see pmap.h
971
972LMMUenable_end:
973
974	lea	_ASM_LABEL(tmpstk),%sp	| give ourselves a temporary stack
975	jbsr	_C_LABEL(start_c_finish)
976
977/* set kernel stack, user SP */
978	movl	_C_LABEL(lwp0uarea),%a1	| grab lwp0 uarea
979	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
980	movl	#USRSTACK-4,%a2
981	movl	%a2,%usp		| init user SP
982	movl	%a2,%a1@(PCB_USP)	| and save it
983	clrw	%a1@(PCB_FLAGS)		| clear flags
984#ifdef FPCOPROC
985	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
986|WRONG!	movl	%a1,%sp@-
987|	pea	%a1@(PCB_FPCTX)
988|	jbsr	_C_LABEL(m68881_restore)	| restore it (does not kill a1)
989|	addql	#4,%sp
990#endif
991/* flush TLB and turn on caches */
992
993	jbsr	_C_LABEL(_TBIA)		| invalidate TLB
994	movl	#CACHE_ON,%d0
995	tstl	%d5
996	jeq	Lcacheon
997| is this needed? MLH
998	.word	0xf4f8			| cpusha bc - push & invalidate caches
999	movl	#CACHE40_ON,%d0
1000#ifdef M68060
1001	cmpl	#CPU_68060,_C_LABEL(cputype)
1002	jne	Lcacheon
1003	movl	#CACHE60_ON,%d0
1004#endif
1005Lcacheon:
1006	movc	%d0,%cacr		| clear cache(s)
1007/* final setup for C code */
1008
1009	movw	#PSL_LOWIPL,%sr		| lower SPL
1010
1011	movl	%d7,_C_LABEL(boothowto)	| save reboot flags
1012/*
1013 * Create a fake exception frame that returns to user mode,
1014 * make space for the rest of a fake saved register set, and
1015 * pass the first available RAM and a pointer to the register
1016 * set to "main()".  "main()" will do an "execve()" using that
1017 * stack frame.
1018 * When "main()" returns, we're running in process 1 and have
1019 * successfully executed the "execve()".  We load up the registers from
1020 * that set; the "rte" loads the PC and PSR, which jumps to "init".
1021 */
1022  	clrw	%sp@-			| vector offset/frame type
1023	clrl	%sp@-			| PC - filled in by "execve"
1024  	movw	#PSL_USER,%sp@-		| in user mode
1025	clrl	%sp@-			| stack adjust count
1026	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
1027	lea	_C_LABEL(lwp0),%a0		| lwp0 in a0
1028	movl	%sp,%a0@(L_MD_REGS)	| save frame for lwp0
1029	movl	%usp,%a1
1030	movl	%a1,%sp@(FR_SP)		| save user stack pointer in frame
1031	pea	%sp@			| addr of space for D0
1032
1033	jbsr	_C_LABEL(main)		| main(firstaddr, r0)
1034	addql	#4,%sp			| pop args
1035
1036	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
1037	jne	Lnoflush		| no, skip
1038	.word	0xf478			| cpusha dc
1039	.word	0xf498			| cinva ic, also clears the 060 btc
1040Lnoflush:
1041	movl	%sp@(FR_SP),%a0		| grab and load
1042	movl	%a0,%usp		|   user SP
1043	moveml	%sp@+,%d0-%d7/%a0-%a6	| load most registers (all but SSP)
1044	addql	#8,%sp			| pop SSP and stack adjust count
1045  	rte
1046
1047/*
1048 * Primitives
1049 */
1050
1051/*
1052 * non-local gotos
1053 */
1054ENTRY(qsetjmp)
1055	movl	%sp@(4),%a0	| savearea pointer
1056	lea	%a0@(40),%a0	| skip regs we do not save
1057	movl	%a6,%a0@+	| save FP
1058	movl	%sp,%a0@+	| save SP
1059	movl	%sp@,%a0@	| and return address
1060	moveq	#0,%d0		| return 0
1061	rts
1062
1063/*
1064 * Use common m68k process/lwp switch and context save subroutines.
1065 */
1066#include <m68k/m68k/switch_subr.s>
1067
1068ENTRY(ecacheon)
1069	rts
1070
1071ENTRY(ecacheoff)
1072	rts
1073
1074/*
1075 * Check out a virtual address to see if it's okay to write to.
1076 *
1077 * probeva(va, fc)
1078 *
1079 */
1080ENTRY(probeva)
1081	movl	%sp@(8),%d0
1082	movec	%d0,%dfc
1083	movl	%sp@(4),%a0
1084	.word	0xf548				| ptestw (a0)
1085	moveq	#FC_USERD,%d0			| restore DFC to user space
1086	movc	%d0,%dfc
1087	.word	0x4e7a,0x0805			| movec  MMUSR,d0
1088	rts
1089
1090/*
1091 * Handle the nitty-gritty of rebooting the machine.
1092 *
1093 */
1094#if defined(P5PPC68KBOARD)
1095	.data
1096GLOBAL(p5ppc)
1097	.long	0
1098	.text
1099#endif
1100
1101ENTRY_NOPROFILE(doboot)
1102	movl	#CACHE_OFF,%d0
1103	cmpl	#MMU_68040,_C_LABEL(mmutype)	| is it 68040
1104	jne	Ldoboot0
1105	.word	0xf4f8			| cpusha bc - push and invalidate caches
1106	nop
1107	movl	#CACHE40_OFF,%d0
1108Ldoboot0:
1109	movc	%d0,%cacr			| disable on-chip cache(s)
1110
1111	movw	#0x2700,%sr			| cut off any interrupts
1112
1113#if defined(P5PPC68KBOARD)
1114	tstl	_C_LABEL(p5ppc)
1115	jne	Lp5ppcboot
1116#endif
1117#if defined(DRACO)
1118	cmpb	#0x7d,_C_LABEL(machineid)
1119	jeq	LdbOnDraCo
1120#endif
1121
1122	| clear first 4k of CHIPMEM
1123	movl	_C_LABEL(CHIPMEMADDR),%a0
1124	movl	%a0,%a1
1125	movl	#1024,%d0
1126Ldb1:
1127	clrl	%a0@+
1128	dbra	%d0,Ldb1
1129
1130	| now, copy the following code over
1131|	lea	%a1@(Ldoreboot),%a0	| KVA starts at 0, CHIPMEM is phys 0
1132|	lea	%a1@(Ldorebootend),%a1
1133|	lea	%pc@(Ldoreboot-.+2),%a0
1134|	addl	%a1,%a0
1135|	lea	%a0@(128),%a1
1136|	lea	%pc@(Ldoreboot-.+2),%a2
1137	lea	Ldoreboot,%a2
1138	lea	Ldorebootend,%a0
1139	addl	%a1,%a0
1140	addl	%a2,%a1
1141	exg	%a0,%a1
1142Ldb2:
1143	movel	%a2@+,%a0@+
1144	cmpl	%a1,%a0
1145	jle	Ldb2
1146
1147	| ok, turn off MMU..
1148Ldoreboot:
1149	cmpl	#MMU_68040,_C_LABEL(mmutype)	| is it 68040
1150 	jeq	Lmmuoff040
1151	lea	_ASM_LABEL(zero),%a0
1152	pmove	%a0@,%tc		| Turn off MMU
1153	lea	_ASM_LABEL(nullrp),%a0
1154	pmove	%a0@,%crp		| Turn off MMU some more
1155	pmove	%a0@,%srp		| Really, really, turn off MMU
1156	jra	Ldoboot1
1157Lmmuoff040:
1158	movl	#0,%d0
1159	.word	0x4e7b,0x0003		| movc d0,TC
1160	.word	0x4e7b,0x0806		| movc d0,URP
1161	.word	0x4e7b,0x0807		| movc d0,SRP
1162Ldoboot1:
1163
1164	| this weird code is the OFFICIAL way to reboot an Amiga ! ..
1165	lea	0x1000000,%a0
1166	subl	%a0@(-0x14),%a0
1167	movl	%a0@(4),%a0
1168	subl	#2,%a0
1169	cmpw	#0x4e70,%a0@		| 68040 kludge: if ROM entry is not
1170	jne	Ldoreset		| a reset, do the reset here
1171	jmp	%a0@			| otherwise, jump to the ROM to reset
1172	| reset needs to be on longword boundary
1173	nop
1174#ifdef __ELF__
1175	.align	4
1176#else
1177	.align	2
1178#endif
1179Ldoreset:
1180	| reset unconfigures all memory!
1181	reset
1182	| now rely on prefetch for next jmp
1183	jmp	%a0@
1184	| NOT REACHED
1185
1186#if defined(P5PPC68KBOARD)
1187Lp5ppcboot:
1188| The Linux-Apus boot code does it in a similar way
1189| For 040 on uncached pages, eieio can be replaced by nothing.
1190	movl	_C_LABEL(ZTWOROMADDR),%a0
1191	lea	%a0@(0xf60000-0xd80000),%a0
1192	movb	#0x60,%a0@(0x20)
1193	movb	#0x50,%a0@(0x20)
1194	movb	#0x30,%a0@(0x20)
1195	movb	#0x40,%a0@(0x18)
1196	movb	#0x04,%a0@
1197Lwaithere:
1198	jra	Lwaithere
1199#endif
1200
1201#ifdef DRACO
1202LdbOnDraCo:
1203| we use a TTR. We want to boot even if half of us is already dead.
1204
1205	movl	_C_LABEL(boot_fphystart), %d0
1206	lea	LdoDraCoBoot, %a0
1207	lea	%a0@(%d0),%a0
1208	andl	#0xFF000000,%d0
1209	orl	#0x0000C044,%d0	| enable, supervisor, CI, RO
1210	.word	0x4e7b,0x0004	| movc d0,ITT0
1211	jmp	%a0@
1212
1213#ifdef __ELF__
1214	.align	4
1215#else
1216	.align	2
1217#endif
1218LdoDraCoBoot:
1219| turn off MMU now ... were more ore less guaranteed to run on 040/060:
1220	movl	#0,%d0
1221	.word	0x4e7b,0x0003	| movc d0,TC
1222	.word	0x4e7b,0x0806	| movc d0,URP
1223	.word	0x4e7b,0x0807	| movc d0,SRP
1224	.word	0x4e7b,0x0004	| movc d0,ITT0
1225	nop
1226| map in boot ROM @0:
1227	reset
1228| and simulate what a reset exception would have done.
1229	movl	4,%a0
1230	movl	0,%a7
1231	jmp	%a0@
1232	| NOT REACHED
1233#endif
1234/*
1235 * Reboot directly into a new kernel image.
1236 * kernel_reload(image, image_size, entry,
1237 *		 fastram_start, fastram_size, chipram_start, esym, eclockfreq)
1238 */
1239ENTRY_NOPROFILE(kernel_reload)
1240	lea	Lreload_copy,%a0	| cursory validity check of new kernel
1241	movl	%a0@,%d0		|  to see if the kernel reload code
1242	addl	%sp@(4),%a0		|  in new image matches running kernel
1243	cmpl	%a0@,%d0
1244	jeq	Lreload_ok
1245	rts				| It doesn't match - can't reload
1246Lreload_ok:
1247	jsr	_C_LABEL(bootsync)
1248	CUSTOMADDR(%a5)
1249
1250	movew	#(1<<9),%a5@(0x096)	| disable DMA (before clobbering chipmem)
1251
1252	movl	#CACHE_OFF,%d0
1253	cmpl	#MMU_68040,_C_LABEL(mmutype)
1254	jne	Lreload1
1255	.word	0xf4f8		| cpusha bc - push and invalidate caches
1256	nop
1257	movl	#CACHE40_OFF,%d0
1258Lreload1:
1259	movc	%d0,%cacr		| disable on-chip cache(s)
1260
1261	movw	#0x2700,%sr		| cut off any interrupts
1262	movel	_C_LABEL(boothowto),%d7	| save boothowto
1263	movel	_C_LABEL(machineid),%d5	| (and machineid)
1264
1265	movel	%sp@(16),%a0		| load memory parameters
1266	movel	%sp@(20),%d0
1267	movel	%sp@(24),%d1
1268	movel	%sp@(28),%a4		| esym
1269	movel	%sp@(32),%d4		| eclockfreq
1270	movel	%sp@(36),%d3		| AGA mode
1271	movel	%sp@(40),%a2		| sync inhibit flags
1272	movel	%sp@(44),%d6		| boot partition offset
1273
1274	movel	%sp@(12),%a6		| find entrypoint (a6)
1275
1276	movel	%sp@(4),%a1		| copy kernel to low chip memory
1277	movel	%sp@(8),%d2
1278	movl	_C_LABEL(CHIPMEMADDR),%a3
1279Lreload_copy:
1280	movel	%a1@+,%a3@+
1281	subl	#4,%d2
1282	jcc	Lreload_copy
1283
1284	| ok, turn off MMU..
1285	cmpl	#MMU_68040,_C_LABEL(mmutype)
1286	jeq	Lreload040
1287	lea	_ASM_LABEL(zero),%a3
1288	pmove	%a3@,%tc		| Turn off MMU
1289	lea	_ASM_LABEL(nullrp),%a3
1290	pmove	%a3@,%crp		| Turn off MMU some more
1291	pmove	%a3@,%srp		| Really, really, turn off MMU
1292	jra	Lreload2
1293Lreload040:
1294	movl	#0,%d2
1295	.word	0x4e7b,0x2003	| movc d2,TC
1296	.word	0x4e7b,0x2806	| movc d2,URP
1297	.word	0x4e7b,0x2807	| movc d2,SRP
1298Lreload2:
1299
1300	moveq	#0,%d2			| clear unused registers
1301	subl	%a1,%a1
1302	subl	%a3,%a3
1303	subl	%a5,%a5
1304	jmp	%a6@			| start new kernel
1305
1306
1307| A do-nothing MMU root pointer (includes the following long as well)
1308
1309ASLOCAL(nullrp)
1310	.long	0x7fff0001
1311ASLOCAL(zero)
1312	.long	0
1313Ldorebootend:
1314
1315#ifdef __ELF__
1316	.align 4
1317#else
1318	.align 2
1319#endif
1320	nop
1321ENTRY_NOPROFILE(delay)
1322ENTRY_NOPROFILE(DELAY)
1323	movql #10,%d1		| 2 +2
1324	movl %sp@(4),%d0	| 4 +4
1325	lsll %d1,%d0		| 8 +2
1326	movl _C_LABEL(delaydivisor),%d1	| A +6
1327Ldelay:				| longword aligned again.
1328	subl %d1,%d0
1329	jcc Ldelay
1330	rts
1331
1332#ifdef M68060
1333ENTRY_NOPROFILE(intemu60)
1334	addql	#1,L60iem
1335	jra	_C_LABEL(I_CALL_TOP)+128+0x00
1336ENTRY_NOPROFILE(fpiemu60)
1337	addql	#1,L60fpiem
1338	jra	_C_LABEL(FP_CALL_TOP)+128+0x30
1339ENTRY_NOPROFILE(fpdemu60)
1340	addql	#1,L60fpdem
1341	jra	_C_LABEL(FP_CALL_TOP)+128+0x38
1342ENTRY_NOPROFILE(fpeaemu60)
1343	addql	#1,L60fpeaem
1344	jra	_C_LABEL(FP_CALL_TOP)+128+0x40
1345#endif
1346
1347	.data
1348	.space	PAGE_SIZE
1349	.align	4
1350ASLOCAL(tmpstk)
1351
1352GLOBAL(mmutype)
1353	.long	MMU_68851
1354GLOBAL(cputype)
1355	.long	CPU_68020
1356GLOBAL(ectype)
1357	.long	EC_NONE
1358GLOBAL(fputype)
1359	.long	FPU_NONE
1360GLOBAL(delaydivisor)
1361	.long	12		| should be enough for 80 MHz 68060
1362				| will be adapted to other CPUs in
1363				| start_c_cleanup and calibrated
1364				| at clock attach time.
1365#ifdef DEBUG
1366ASGLOBAL(fulltflush)
1367	.long	0
1368ASGLOBAL(fullcflush)
1369	.long	0
1370ASGLOBAL(timebomb)
1371	.long	0
1372#endif
1373/* interrupt counters */
1374GLOBAL(intrnames)
1375	.asciz	"spur"		| spurious interrupt
1376	.asciz	"tbe/soft"	| serial TBE & software
1377	.asciz	"kbd/ports"	| keyboard & PORTS
1378	.asciz	"vbl"		| vertical blank
1379	.asciz	"audio"		| audio channels
1380	.asciz	"rbf"		| serial receive
1381	.asciz	"exter"		| EXTERN
1382	.asciz	"nmi"		| non-maskable
1383	.asciz	"clock"		| clock interrupts
1384	.asciz	"spur6"		| spurious level 6
1385#ifdef DRACO
1386	.asciz	"kbd/soft"	| 1: native keyboard, soft ints
1387	.asciz	"cia/zbus"	| 2: cia, PORTS
1388	.asciz	"lclbus"	| 3: local bus, e.g. Altais vbl
1389	.asciz	"drscsi"	| 4: mainboard scsi
1390	.asciz	"superio"	| 5: superio chip
1391	.asciz	"lcl/zbus"	| 6: lcl/zorro lev6
1392	.asciz	"buserr"	| 7: nmi: bus timeout
1393#endif
1394#ifdef M68060
1395	.asciz	"60intemu"
1396	.asciz	"60fpiemu"
1397	.asciz	"60fpdemu"
1398	.asciz	"60fpeaemu"
1399	.asciz	"60bpe"
1400#endif
1401#ifdef FPU_EMULATE
1402	.asciz	"fpe"
1403#endif
1404GLOBAL(eintrnames)
1405#ifdef __ELF__
1406	.align	4
1407#else
1408	.align	2
1409#endif
1410GLOBAL(intrcnt)
1411	.long	0,0,0,0,0,0,0,0,0,0
1412#ifdef DRACO
1413ASLOCAL(Drintrcnt)
1414	.long	0,0,0,0,0,0,0
1415#endif
1416#ifdef M68060
1417L60iem:		.long	0
1418L60fpiem:	.long	0
1419L60fpdem:	.long	0
1420L60fpeaem:	.long	0
1421L60bpe:		.long	0
1422#endif
1423#ifdef FPU_EMULATE
1424Lfpecnt:	.long	0
1425#endif
1426GLOBAL(eintrcnt)
1427