xref: /netbsd-src/sys/arch/mvme68k/mvme68k/locore.s (revision cac8e449158efc7261bebc8657cbb0125a2cfdde)
1/*	$NetBSD: locore.s,v 1.99 2007/10/17 19:55:48 garbled Exp $	*/
2
3/*
4 * Copyright (c) 1980, 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * from: Utah $Hdr: locore.s 1.66 92/12/22$
36 *
37 *	@(#)locore.s	8.6 (Berkeley) 5/27/94
38 */
39/*
40 * Copyright (c) 1988 University of Utah.
41 *
42 * This code is derived from software contributed to Berkeley by
43 * the Systems Programming Group of the University of Utah Computer
44 * Science Department.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 *    notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 *    notice, this list of conditions and the following disclaimer in the
53 *    documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 *    must display the following acknowledgement:
56 *	This product includes software developed by the University of
57 *	California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 *    may be used to endorse or promote products derived from this software
60 *    without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
73 *
74 * from: Utah $Hdr: locore.s 1.66 92/12/22$
75 *
76 *	@(#)locore.s	8.6 (Berkeley) 5/27/94
77 */
78
79#include "opt_compat_netbsd.h"
80#include "opt_compat_svr4.h"
81#include "opt_compat_sunos.h"
82#include "opt_fpsp.h"
83#include "opt_ddb.h"
84#include "opt_kgdb.h"
85#include "opt_lockdebug.h"
86
87#include "assym.h"
88#include <machine/asm.h>
89#include <machine/trap.h>
90
91#include "ksyms.h"
92
93/*
94 * Temporary stack for a variety of purposes.
95 * Try and make this the first thing is the data segment so it
96 * is page aligned.  Note that if we overflow here, we run into
97 * our text segment.
98 */
99	.data
100	.space	PAGE_SIZE
101ASLOCAL(tmpstk)
102
103ASLOCAL(bug_vbr)
104	.long	0
105
106#include <mvme68k/mvme68k/vectors.s>
107
108
109/*
110 * Macro to relocate a symbol, used before MMU is enabled.
111 */
112#define	_RELOC(var, ar)		\
113	lea	var,ar
114
115#define	RELOC(var, ar)		_RELOC(_C_LABEL(var), ar)
116#define	ASRELOC(var, ar)	_RELOC(_ASM_LABEL(var), ar)
117
118/*
119 * Macro to call into the Bug ROM monitor
120 */
121#define	CALLBUG(func)	\
122	trap #15; .short func
123
124/*
125 * Initialization
126 *
127 * The bootstrap loader loads us in starting at 0, and VBR is non-zero.
128 * On entry, args on stack are boot device, boot filename, console unit,
129 * boot flags (howto), boot device name, filesystem type name.
130 */
131BSS(lowram,4)
132BSS(esym,4)
133
134	.globl	_C_LABEL(edata)
135	.globl	_C_LABEL(etext),_C_LABEL(end)
136
137
138/*
139 * This is for kvm_mkdb, and should be the address of the beginning
140 * of the kernel text segment (not necessarily the same as kernbase).
141 */
142	.text
143GLOBAL(kernel_text)
144
145/*
146 * start of kernel and .text!
147 */
148ASENTRY_NOPROFILE(start)
149	movw	#PSL_HIGHIPL,%sr	| no interrupts
150	movl	#0,%a5			| RAM starts at 0 (a5)
151	movl	%sp@(4), %d7		| get boothowto
152	movl	%sp@(8), %d6		| get bootaddr
153	movl	%sp@(12),%d5		| get bootctrllun
154	movl	%sp@(16),%d4		| get bootdevlun
155	movl	%sp@(20),%d3		| get bootpart
156	movl	%sp@(24),%d2		| get esyms
157
158	RELOC(bootpart,%a0)
159	movl	%d3, %a0@		| save bootpart
160	RELOC(bootdevlun,%a0)
161	movl	%d4, %a0@		| save bootdevlun
162	RELOC(bootctrllun,%a0)
163	movl	%d5, %a0@		| save booctrllun
164	RELOC(bootaddr,%a0)
165	movl	%d6, %a0@		| save bootaddr
166	RELOC(boothowto,%a0)
167	movl	%d7, %a0@		| save boothowto
168	/* note: d3-d7 free, d2 still in use */
169
170	ASRELOC(tmpstk, %a0)
171	movl	%a0,%sp			| give ourselves a temporary stack
172
173	RELOC(edata,%a0)		| clear out BSS
174	movl	#_C_LABEL(end) - 4, %d0	| (must be <= 256 kB)
175	subl	#_C_LABEL(edata), %d0
176	lsrl	#2,%d0
1771:	clrl	%a0@+
178	dbra	%d0,1b
179
180	RELOC(esym, %a0)
181	movl	%d2,%a0@		| store end of symbol table
182	/* d2 now free */
183	RELOC(lowram, %a0)
184	movl	%a5,%a0@		| store start of physical memory
185	movl	#CACHE_OFF,%d0
186	movc	%d0,%cacr		| clear and disable on-chip cache(s)
187
188	/* ask the Bug what we are... */
189	clrl	%sp@-
190	CALLBUG(MVMEPROM_GETBRDID)
191	movl	%sp@+,%a1
192
193	/* copy to a struct mvmeprom_brdid */
194	movl	#MVMEPROM_BRDID_SIZE,%d0
195	RELOC(boardid,%a0)
1961:	movb	%a1@+,%a0@+
197	subql	#1,%d0
198	jbne	1b
199
200	/*
201	 * Grab the model number from _boardid and use the value
202	 * to setup machineid, cputype, and mmutype.
203	 */
204	clrl	%d0
205	RELOC(boardid,%a1)
206	movw	%a1@(MVMEPROM_BRDID_MODEL_OFFSET),%d0
207	RELOC(machineid,%a0)
208	movl	%d0,%a0@
209
210	ASRELOC(Lbrdid2mach,%a0)
211Lbrdmatch:
212	cmpw	%a0@+,%d0
213	jbeq	Lgotmatch
214	addw	#0x12,%a0		| Each entry is 20-2 bytes long
215	tstw	%a0@
216	jbne	Lbrdmatch
217
218	/*
219	 * If we fall to here, the board is not supported.
220	 * Print a warning, then drop out to the Bug.
221	 */
222	movl	#Lenotconf,%sp@-
223	movl	#Lnotconf,%sp@-
224	CALLBUG(MVMEPROM_OUTSTRCRLF)
225	addql	#8,%sp			| clean up stack after call
226
227	CALLBUG(MVMEPROM_EXIT)
228	/* NOTREACHED */
229
230	.data
231Lnotconf:
232	.ascii	"Sorry, the kernel isn't configured for this model."
233Lenotconf:
234	.even
235
236ASLOCAL(Lbrdid2mach)
237#ifdef MVME147
238	.word	MVME_147
239	.word		CPU_68030
240	.word		MMU_68030
241	.word		FPU_68882
242	.long		_C_LABEL(busaddrerr2030)
243	.long		_C_LABEL(busaddrerr2030)
244	.long		Linit147
245#endif
246#ifdef MVME162
247	.word	MVME_162
248	.word		CPU_68040
249	.word		MMU_68040
250	.word		FPU_68040
251	.long		_C_LABEL(buserr40)
252	.long		_C_LABEL(addrerr4060)
253	.long		Linit1x2
254#endif
255#ifdef MVME167
256	.word	MVME_167
257	.word		CPU_68040
258	.word		MMU_68040
259	.word		FPU_68040
260	.long		_C_LABEL(buserr40)
261	.long		_C_LABEL(addrerr4060)
262	.long		Linit1x7
263#endif
264#ifdef MVME172
265	.word	MVME_172
266	.word		CPU_68060
267	.word		MMU_68040
268	.word		FPU_68060
269	.long		_C_LABEL(buserr60)
270	.long		_C_LABEL(addrerr4060)
271	.long		Linit1x2
272#endif
273#ifdef MVME177
274	.word	MVME_177
275	.word		CPU_68060
276	.word		MMU_68040
277	.word		FPU_68060
278	.long		_C_LABEL(buserr60)
279	.long		_C_LABEL(addrerr4060)
280	.long		Linit1x7
281#endif
282	.word	0
283	.text
284	.even
285
286/*
287 * We have a match, so the kernel should support this board.
288 * a0 points to the matching entry in Lbrdid2mach.
289 */
290Lgotmatch:
291	movew	%a0@+,%d1		| Copy the CPU type
292	extl	%d1
293	RELOC(cputype,%a1)
294	movel	%d1,%a1@
295	movew	%a0@+,%d1		| Copy the MMU type
296	extl	%d1
297	RELOC(mmutype,%a1)
298	movel	%d1,%a1@
299	movew	%a0@+,%d1		| Copy the FPU type
300	extl	%d1
301	RELOC(fputype,%a1)
302	movel	%d1,%a1@
303	movel	%a0@+,%a2		| Fetch the bus error vector
304	RELOC(vectab,%a1)
305	movl	%a2,%a1@(8)
306	movel	%a0@+,%a2		| Fetch the address error vector
307	movl	%a2,%a1@(12)
308	movel	%a0@,%a0		| Finally, the board-specific init code
309	jmp	%a0@
310
311
312#ifdef MVME147
313Linit147:
314	/* MVME-147 - 68030 CPU/MMU, 68882 FPU */
315	/* XXXCDC SHUTUP 147 CALL */
316	movb	#0, 0xfffe1026		| serial interrupt off
317	movb	#0, 0xfffe1018		| timer 1 off
318	movb	#0, 0xfffe1028		| ethernet off
319	/* XXXCDC SHUTUP 147 CALL */
320
321	/* Save our ethernet address */
322	RELOC(mvme_ea, %a0)
323	lea	0xfffe0778,%a1		| XXXCDC -- HARDWIRED HEX
324	movb	#0x08,%a0@+
325	clrb	%a0@+
326	movb	#0x3e,%a0@+
327	movql	#0x0f,%d0
328	andb	%a1@+,%d0
329	orb	#0x20,%d0
330	movb	%d0,%a0@+
331	movb	%a1@+,%a0@+
332	movb	%a1@,%a0@
333
334	/*
335	 * Fix up the physical addresses of the MVME147's onboard
336	 * I/O registers.
337	 */
338	RELOC(intiobase_phys, %a0);
339	movl	#INTIOBASE147,%a0@
340	RELOC(intiotop_phys, %a0);
341	movl	#INTIOTOP147,%a0@
342
343	/* initialise list of physical memory segments for pmap_bootstrap */
344	RELOC(phys_seg_list, %a0)
345	movl	%a5,%a0@		| phys_seg_list[0].ps_start
346	movl	0xfffe0774,%d1		| End + 1 of onboard memory
347	movl	%d1,%a0@(4)		| phys_seg_list[0].ps_end
348	clrl	%a0@(8)			| phys_seg_list[0].ps_startpage
349
350	/* offboard RAM */
351	clrl	%a0@(0x0c)		| phys_seg_list[1].ps_start
352	movl	#PAGE_SIZE-1,%d0
353	addl	0xfffe0764,%d0		| Start of offboard segment
354	andl	#-PAGE_SIZE,%d0		| Round up to page boundary
355	jbeq	Lsavmaxmem		| Jump if none defined
356	movl	#PAGE_SIZE,%d1		| Note: implicit '+1'
357	addl	0xfffe0768,%d1		| End of offboard segment
358	andl	#-PAGE_SIZE,%d1		| Round up to page boundary
359	cmpl	%d1,%d0			| Quick and dirty validity check
360	jbcs	Loff_ok			| Yup, looks good.
361	movel	%a0@(4),%d1		| Just use onboard RAM otherwise
362	jbra	Lsavmaxmem
363Loff_ok:
364	movl	%d0,%a0@(0x0c)		| phys_seg_list[1].ps_start
365	movl	%d1,%a0@(0x10)		| phys_seg_list[1].ps_end
366	clrl	%a0@(0x14)		| phys_seg_list[1].ps_startpage
367
368	/*
369	 * Offboard RAM needs to be cleared to zero to initialise parity
370	 * on most VMEbus RAM cards. Without this, some cards will buserr
371	 * when first read.
372	 */
373	movel	%d0,%a0			| offboard start address again.
374Lclearoff:
375	clrl	%a0@+			| zap a word
376	cmpl	%a0,%d1			| reached end?
377	jbne	Lclearoff
378
379Lsavmaxmem:
380	moveq	#PGSHIFT,%d2
381	lsrl	%d2,%d1			| convert to page (click) number
382	RELOC(maxmem, %a0)
383	movl	%d1,%a0@		| save as maxmem
384	jra	Lstart1
385#endif
386
387#if defined(MVME162) || defined(MVME172)
388Linit1x2:
389	/* MVME-162 - 68040 CPU/MMU/FPU */
390	/* MVME-172 - 68060 CPU/MMU/FPU */
391
392	/*
393	 * Verify the user has removed the GPIO#0 jumper...
394	 */
395	btst	#0,0xfff4202d		| Clear == jumper installed
396	jne	1f			| Ok.
397
398	movl	#Le1x2jump,%sp@-
399	movl	#L1x2jump,%sp@-
400	CALLBUG(MVMEPROM_OUTSTRCRLF)
401	addql	#8,%sp			| clean up stack after call
402
403	CALLBUG(MVMEPROM_EXIT)
404	/* NOTREACHED */
405
4061:
407	/*
408	 * Determine if this board has a VMEchip2
409	 */
410	btst	#1,0xfff4202e		| VMEchip2 presence detect
411	jne	2f			| Jump if it doesn't exist.
412
413	/*
414	 * Disable all interrupts from VMEchip2. This is especially
415	 * useful when the kernel doesn't have the VMEchip2 driver
416	 * configured. If we didn't do this, then we're at the mercy
417	 * of whatever VMEchip2 interrupts the ROM set up. For example,
418	 * hitting the ABORT switch could kill the system...
419	 */
420	movl	0xfff40088,%d0
421	andl	#0xff7fffff,%d0		| Clear 'MIEN'
422	movl	%d0,0xfff40088
4232:
424	/*
425	 * Determine how much onboard memory is installed
426	 */
427	movql	#0x07,%d0
428	andb	0xfff42024,%d0
429	ASRELOC(Ldramsize1x2,%a0)
430	movl	%a0@(%d0:w:4),%d1	| Lookup the size
431	jeq	Lmemcquery		| Assume a MEMC chip if this is zero.
432	jra	Lis1xx_common
433
434	.data
435	.even
436	/*
437	 * Table of DRAM register size values -> actual size in bytes
438	 */
439ASLOCAL(Ldramsize1x2)
440	.long	0x00100000
441	.long	0x00200000
442	.long	0x00000000
443	.long	0x00400000
444	.long	0x00400000
445	.long	0x00800000
446	.long	0x00000000
447	.long	0x01000000
448
449L1x2jump:
450	.ascii	"You must remove the jumper from pins 15-16 of J22 (mvme162)"
451	.ascii	"or pins 1-2\015\012"
452	.ascii	"J11 (mvme162-LX) first! See NetBSD/mvme68k FAQ for details."
453Le1x2jump:
454	.even
455
456	.text
457#endif
458
459#if defined(MVME167) || defined(MVME177)
460Linit1x7:
461	/* MVME-167 - 68040 CPU/MMU/FPU */
462	/* MVME-177 - 68060 CPU/MMU/FPU */
463
464	/*
465	 * Verify the user has removed the GPIO#0 jumper...
466	 */
467	movel	#0x00000001,%d0
468	andl	0xfff40088,%d0		| Clear == jumper installed
469	jne	1f			| Ok.
470
471	movl	#Le1x7jump,%sp@-
472	movl	#L1x7jump,%sp@-
473	CALLBUG(MVMEPROM_OUTSTRCRLF)
474	addql	#8,%sp			| clean up stack after call
475
476	CALLBUG(MVMEPROM_EXIT)
477	/* NOTREACHED */
478
4791:
480	/*
481	 * Disable all interrupts from VMEchip2. This is especially
482	 * useful when the kernel doesn't have the VMEchip2 driver
483	 * configured. If we didn't do this, then we're at the mercy
484	 * of whatever VMEchip2 interrupts the ROM set up. For example,
485	 * hitting the ABORT switch could kill the system...
486	 */
487	movl	0xfff40088,%d0
488	andl	#0xff7fffff,%d0		| Clear 'MIEN'
489	movl	%d0,0xfff40088
490
491	.data
492	.even
493L1x7jump:
494	.ascii	"You must remove the jumper from pins 1-2 of J1!\015\012"
495	.ascii	"See NetBSD/mvme68k FAQ for details."
496Le1x7jump:
497	.even
498
499	.text
500#endif
501
502#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
503Lmemcquery:
504	/*
505	 * Figure out the size of onboard DRAM by querying
506	 * the memory controller ASIC(s)
507	 */
508	lea	0xfff43008,%a0		| MEMC040/MEMECC Controller #1
509	jbsr	memc040read
510	movl	%d0,%d1
511
512	lea	0xfff43108,%a0		| MEMC040/MEMECC Controller #2
513	jbsr	memc040read
514	addl	%d0,%d1
515
516Lis1xx_common:
517	/* Save our ethernet address */
518	RELOC(mvme_ea, %a0)
519	lea	0xfffc1f2c,%a1
520	movb	%a1@+,%a0@+
521	movb	%a1@+,%a0@+
522	movb	%a1@+,%a0@+
523	movb	%a1@+,%a0@+
524	movb	%a1@+,%a0@+
525	movb	%a1@,%a0@
526
527	/*
528	 * Fix up the physical addresses of the onboard
529	 * I/O registers.
530	 */
531	RELOC(intiobase_phys, %a0);
532	movl	#INTIOBASE1xx,%a0@
533	RELOC(intiotop_phys, %a0);
534	movl	#INTIOTOP1xx,%a0@
535
536	/*
537	 * Initialise first physical memory segment with onboard RAM details
538	 */
539	RELOC(phys_seg_list, %a0)
540	movl	%a5,%a0@		| phys_seg_list[0].ps_start
541	movl	%d1,%a0@(4)		| phys_seg_list[0].ps_end
542	clrl	%a0@(8)			| phys_seg_list[0].ps_startpage
543
544	/* offboard RAM */
545	clrl	%a0@(0x0c)		| phys_seg_list[1].ps_start
546	movl	#PAGE_SIZE-1,%d0
547	addl	0xfffc0000,%d0		| Start of offboard segment
548	andl	#-PAGE_SIZE,%d0		| Round up to page boundary
549	jbeq	Ldone1xx		| Jump if none defined
550	movl	#PAGE_SIZE,%d1		| Note: implicit '+1'
551	addl	0xfffc0004,%d1		| End of offboard segment
552	andl	#-PAGE_SIZE,%d1		| Round up to page boundary
553	cmpl	%d1,%d0			| Quick and dirty validity check
554	jbcs	Lramsave1xx		| Yup, looks good.
555	movel	%a0@(4),%d1		| Just use onboard RAM otherwise
556	jbra	Ldone1xx
557
558Lramsave1xx:
559	movl	%d0,%a0@(0x0c)		| phys_seg_list[1].ps_start
560	movl	%d1,%a0@(0x10)		| phys_seg_list[1].ps_end
561	clrl	%a0@(0x14)		| phys_seg_list[1].ps_startpage
562
563	/*
564	 * Offboard RAM needs to be cleared to zero to initialise parity
565	 * on most VMEbus RAM cards. Without this, some cards will buserr
566	 * when first read.
567	 */
568	movel	%d0,%a0			| offboard start address again.
569Lramclr1xx:
570	clrl	%a0@+			| zap a word
571	cmpl	%a0,%d1			| reached end?
572	jbne	Lramclr1xx
573
574Ldone1xx:
575	moveq	#PGSHIFT,%d2
576	lsrl	%d2,%d1			| convert to page (click) number
577	RELOC(maxmem, %a0)
578	movl	%d1,%a0@		| save as maxmem
579
580	/* FALLTHROUGH to Lstart1 */
581#endif
582
583
584Lstart1:
585/* initialize source/destination control registers for movs */
586	moveq	#FC_USERD,%d0		| user space
587	movc	%d0,%sfc		|   as source
588	movc	%d0,%dfc		|   and destination of transfers
589/*
590 * configure kernel and lwp0 VA space so we can get going
591 */
592#if NKSYMS || defined(DDB) || defined(LKM)
593	RELOC(esym,%a0)			| end of static kernel text/data syms
594	movl	%a0@,%d2
595	jne	Lstart2
596#endif
597	movl	#_C_LABEL(end),%d2	| end of static kernel text/data
598Lstart2:
599	addl	#PAGE_SIZE-1,%d2
600	andl	#PG_FRAME,%d2		| round to a page
601	movl	%d2,%a4
602	addl	%a5,%a4			| convert to PA
603	pea	%a5@			| firstpa
604	pea	%a4@			| nextpa
605	RELOC(pmap_bootstrap,%a0)
606	jbsr	%a0@			| pmap_bootstrap(firstpa, nextpa)
607	addql	#8,%sp
608
609/*
610 * Enable the MMU.
611 * Since the kernel is mapped logical == physical, we just turn it on.
612 */
613	RELOC(Sysseg, %a0)		| system segment table addr
614	movl	%a0@,%d1		| read value (a KVA)
615	addl	%a5,%d1			| convert to PA
616	RELOC(mmutype, %a0)
617	cmpl	#MMU_68040,%a0@		| 68040?
618	jne	Lmotommu1		| no, skip
619	.long	0x4e7b1807		| movc d1,srp
620	jra	Lstploaddone
621Lmotommu1:
622	RELOC(protorp, %a0)
623	movl	#0x80000202,%a0@	| nolimit + share global + 4 byte PTEs
624	movl	%d1,%a0@(4)		| + segtable address
625	pmove	%a0@,%srp		| load the supervisor root pointer
626	movl	#0x80000002,%a0@	| reinit upper half for CRP loads
627Lstploaddone:
628	RELOC(mmutype, %a0)
629	cmpl	#MMU_68040,%a0@		| 68040?
630	jne	Lmotommu2		| no, skip
631	moveq	#0,%d0			| ensure TT regs are disabled
632	.long	0x4e7b0004		| movc d0,itt0
633	.long	0x4e7b0005		| movc d0,itt1
634	.long	0x4e7b0006		| movc d0,dtt0
635	.long	0x4e7b0007		| movc d0,dtt1
636	.word	0xf4d8			| cinva bc
637	.word	0xf518			| pflusha
638	movl	#0x8000,%d0
639	.long	0x4e7b0003		| movc d0,tc
640#ifdef M68060
641	RELOC(cputype, %a0)
642	cmpl	#CPU_68060,%a0@		| 68060?
643	jne	Lnot060cache
644	movl	#1,%d0
645	.long	0x4e7b0808		| movcl d0,pcr
646	movl	#0xa0808000,%d0
647	movc	%d0,%cacr		| enable store buffer, both caches
648	jmp	Lenab1
649Lnot060cache:
650#endif
651	movl	#0x80008000,%d0
652	movc	%d0,%cacr		| turn on both caches
653	jmp	Lenab1
654Lmotommu2:
655	movl	#0x82c0aa00,%sp@-	| value to load TC with
656	pmove	%sp@,%tc		| load it
657
658/*
659 * Should be running mapped from this point on
660 */
661Lenab1:
662/* Point the CPU VBR at our vector table */
663	movc	%vbr,%d0		| Preserve Bug's VBR address
664	movl	%d0,_ASM_LABEL(bug_vbr)
665	movl	#_C_LABEL(vectab),%d0	| get our VBR address
666	movc	%d0,%vbr
667/* select the software page size now */
668	lea	_ASM_LABEL(tmpstk),%sp	| temporary stack
669	jbsr	_C_LABEL(uvm_setpagesize)  | select software page size
670/* set kernel stack, user SP, and initial pcb */
671	movl	_C_LABEL(proc0paddr),%a1 | get lwp0 pcb addr
672	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
673	lea	_C_LABEL(lwp0),%a2	| initialize lwp0.p_addr
674	movl	%a2,_C_LABEL(curlwp)	|   and curlwp so that
675	movl	%a1,%a2@(L_ADDR)	|   we don't deref NULL in trap()
676	movl	#USRSTACK-4,%a2
677	movl	%a2,%usp		| init user SP
678	movl	%a1,_C_LABEL(curpcb)	| lwp0 is running
679	tstl	_C_LABEL(fputype)	| Have an FPU?
680	jeq	Lenab2			| No, skip.
681	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
682	movl	%a1,%sp@-
683	jbsr	_C_LABEL(m68881_restore) | restore it (does not kill a1)
684	addql	#4,%sp
685Lenab2:
686	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
687	jeq	Ltbia040		| yes, cache already on
688	pflusha
689	movl	#CACHE_ON,%d0
690	movc	%d0,%cacr		| clear cache(s)
691	jra	Lenab3
692Ltbia040:
693	.word	0xf518
694Lenab3:
695/*
696 * final setup for C code:
697 * Create a fake exception frame so that cpu_fork() can copy it.
698 * main() nevers returns; we exit to user mode from a forked process
699 * later on.
700 */
701	jbsr	_C_LABEL(mvme68k_init)	| additional pre-main initialization
702	movw	#PSL_LOWIPL,%sr		| lower SPL
703	clrw	%sp@-			| vector offset/frame type
704	clrl	%sp@-			| PC - filled in by "execve"
705	movw	#PSL_USER,%sp@-		| in user mode
706	clrl	%sp@-			| stack adjust count and padding
707	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
708	lea	_C_LABEL(lwp0),%a0	| save pointer to frame
709	movl	%sp,%a0@(L_MD_REGS)	|   in lwp0.l_md.md_regs
710
711	jra	_C_LABEL(main)		| main()
712
713#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
714/*
715 * Probe for a memory controller ASIC (MEMC040 or MEMECC) at the
716 * address in a0. If found, return the size in bytes of any RAM
717 * controlled by the ASIC in d0. Otherwise return zero.
718 */
719ASLOCAL(memc040read)
720	moveml	%d1-%d2/%a1-%a2,%sp@-	| save scratch regs
721	movc	%vbr,%d2		| Save vbr
722	RELOC(vectab,%a2)		| Install our own vectab, temporarily
723	movc	%a2,%vbr
724	ASRELOC(Lmemc040berr,%a1)	| get address of bus error handler
725	movl	%a2@(8),%sp@-		| Save current bus error handler addr
726	movl	%a1,%a2@(8)		| Install our own handler
727	movl	%sp,%d0			| Save current stack pointer value
728	movql	#0x07,%d1
729	andb	%a0@,%d1		| Access MEMC040/MEMECC
730	movl	#0x400000,%d0
731	lsll	%d1,%d0			| Convert to memory size, in bytes
732Lmemc040ret:
733	movc	%d2,%vbr		| Restore original vbr
734	movl	%sp@+,%a2@(8)		| Restore original bus error handler
735	moveml  %sp@+,%d1-%d2/%a1-%a2
736	rts
737/*
738 * If the memory controller doesn't exist, we get a bus error trying
739 * to access a0@ above. Control passes here, where we flag 'no bytes',
740 * ditch the exception frame and return as normal.
741 */
742Lmemc040berr:
743	movl	%d0,%sp			| Get rid of the exception frame
744	movql	#0,%d0			| No ASIC at this location, then!
745	jbra	Lmemc040ret		| Done
746#endif
747
748/*
749 * Trap/interrupt vector routines
750 */
751#include <m68k/m68k/trap_subr.s>
752
753#if defined(M68040) || defined(M68060)
754ENTRY_NOPROFILE(addrerr4060)
755	clrl	%sp@-			| stack adjust count
756	moveml	#0xFFFF,%sp@-		| save user registers
757	movl	%usp,%a0		| save the user SP
758	movl	%a0,%sp@(FR_SP)		|   in the savearea
759	movl	%sp@(FR_HW+8),%sp@-
760	clrl	%sp@-			| dummy code
761	movl	#T_ADDRERR,%sp@-	| mark address error
762	jra	_ASM_LABEL(faultstkadj)	| and deal with it
763#endif
764
765#if defined(M68060)
766ENTRY_NOPROFILE(buserr60)
767	clrl	%sp@-			| stack adjust count
768	moveml	#0xFFFF,%sp@-		| save user registers
769	movl	%usp,%a0		| save the user SP
770	movl	%a0,%sp@(FR_SP)		|   in the savearea
771	movel	%sp@(FR_HW+12),%d0	| FSLW
772	btst	#2,%d0			| branch prediction error?
773	jeq	Lnobpe
774	movc	%cacr,%d2
775	orl	#IC60_CABC,%d2		| clear all branch cache entries
776	movc	%d2,%cacr
777	movl	%d0,%d1
778	andl	#0x7ffd,%d1
779	jeq	_ASM_LABEL(faultstkadjnotrap2)
780Lnobpe:
781| we need to adjust for misaligned addresses
782	movl	%sp@(FR_HW+8),%d1	| grab VA
783	btst	#27,%d0			| check for mis-aligned access
784	jeq	Lberr3			| no, skip
785	addl	#28,%d1			| yes, get into next page
786					| operand case: 3,
787					| instruction case: 4+12+12
788	andl	#PG_FRAME,%d1		| and truncate
789Lberr3:
790	movl	%d1,%sp@-
791	movl	%d0,%sp@-		| code is FSLW now.
792	andw	#0x1f80,%d0
793	jeq	Lberr60			| it is a bus error
794	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
795	jra	_ASM_LABEL(faultstkadj)	| and deal with it
796Lberr60:
797	tstl	_C_LABEL(nofault)	| catch bus error?
798	jeq	Lisberr			| no, handle as usual
799	movl	_C_LABEL(nofault),%sp@-	| yes,
800	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
801	/* NOTREACHED */
802#endif
803#if defined(M68040)
804ENTRY_NOPROFILE(buserr40)
805	clrl	%sp@-			| stack adjust count
806	moveml	#0xFFFF,%sp@-		| save user registers
807	movl	%usp,%a0		| save the user SP
808	movl	%a0,%sp@(FR_SP)		|   in the savearea
809	movl	%sp@(FR_HW+20),%d1	| get fault address
810	moveq	#0,%d0
811	movw	%sp@(FR_HW+12),%d0	| get SSW
812	btst	#11,%d0			| check for mis-aligned
813	jeq	Lbe1stpg		| no skip
814	addl	#3,%d1			| get into next page
815	andl	#PG_FRAME,%d1		| and truncate
816Lbe1stpg:
817	movl	%d1,%sp@-		| pass fault address.
818	movl	%d0,%sp@-		| pass SSW as code
819	btst	#10,%d0			| test ATC
820	jeq	Lberr40			| it is a bus error
821	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
822	jra	_ASM_LABEL(faultstkadj)	| and deal with it
823Lberr40:
824	tstl	_C_LABEL(nofault)	| catch bus error?
825	jeq	Lisberr			| no, handle as usual
826	movl	_C_LABEL(nofault),%sp@-	| yes,
827	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
828	/* NOTREACHED */
829#endif
830
831#if defined(M68020) || defined(M68030)
832ENTRY_NOPROFILE(busaddrerr2030)
833	clrl	%sp@-			| stack adjust count
834	moveml	#0xFFFF,%sp@-		| save user registers
835	movl	%usp,%a0		| save the user SP
836	movl	%a0,%sp@(FR_SP)		|   in the savearea
837	moveq	#0,%d0
838	movw	%sp@(FR_HW+10),%d0	| grab SSW for fault processing
839	btst	#12,%d0			| RB set?
840	jeq	LbeX0			| no, test RC
841	bset	#14,%d0			| yes, must set FB
842	movw	%d0,%sp@(FR_HW+10)	| for hardware too
843LbeX0:
844	btst	#13,%d0			| RC set?
845	jeq	LbeX1			| no, skip
846	bset	#15,%d0			| yes, must set FC
847	movw	%d0,%sp@(FR_HW+10)	| for hardware too
848LbeX1:
849	btst	#8,%d0			| data fault?
850	jeq	Lbe0			| no, check for hard cases
851	movl	%sp@(FR_HW+16),%d1	| fault address is as given in frame
852	jra	Lbe10			| thats it
853Lbe0:
854	btst	#4,%sp@(FR_HW+6)	| long (type B) stack frame?
855	jne	Lbe4			| yes, go handle
856	movl	%sp@(FR_HW+2),%d1	| no, can use save PC
857	btst	#14,%d0			| FB set?
858	jeq	Lbe3			| no, try FC
859	addql	#4,%d1			| yes, adjust address
860	jra	Lbe10			| done
861Lbe3:
862	btst	#15,%d0			| FC set?
863	jeq	Lbe10			| no, done
864	addql	#2,%d1			| yes, adjust address
865	jra	Lbe10			| done
866Lbe4:
867	movl	%sp@(FR_HW+36),%d1	| long format, use stage B address
868	btst	#15,%d0			| FC set?
869	jeq	Lbe10			| no, all done
870	subql	#2,%d1			| yes, adjust address
871Lbe10:
872	movl	%d1,%sp@-		| push fault VA
873	movl	%d0,%sp@-		| and padded SSW
874	movw	%sp@(FR_HW+8+6),%d0	| get frame format/vector offset
875	andw	#0x0FFF,%d0		| clear out frame format
876	cmpw	#12,%d0			| address error vector?
877	jeq	Lisaerr			| yes, go to it
878	movl	%d1,%a0			| fault address
879	movl	%sp@,%d0		| function code from ssw
880	btst	#8,%d0			| data fault?
881	jne	Lbe10a
882	movql	#1,%d0			| user program access FC
883					| (we dont separate data/program)
884	btst	#5,%sp@(FR_HW+8)	| supervisor mode?
885	jeq	Lbe10a			| if no, done
886	movql	#5,%d0			| else supervisor program access
887Lbe10a:
888	ptestr	%d0,%a0@,#7		| do a table search
889	pmove	%psr,%sp@		| save result
890	movb	%sp@,%d1
891	btst	#2,%d1			| invalid (incl. limit viol. and berr)?
892	jeq	Lmightnotbemerr		| no -> wp check
893	btst	#7,%d1			| is it MMU table berr?
894	jne	Lisberr1		| yes, needs not be fast.
895Lismerr:
896	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
897	jra	_ASM_LABEL(faultstkadj)	| and deal with it
898Lmightnotbemerr:
899	btst	#3,%d1			| write protect bit set?
900	jeq	Lisberr1		| no: must be bus error
901	movl	%sp@,%d0		| ssw into low word of d0
902	andw	#0xc0,%d0		| Write protect is set on page:
903	cmpw	#0x40,%d0		| was it read cycle?
904	jne	Lismerr			| no, was not WPE, must be MMU fault
905	jra	Lisberr1		| real bus err needs not be fast.
906Lisaerr:
907	movl	#T_ADDRERR,%sp@-	| mark address error
908	jra	_ASM_LABEL(faultstkadj)	| and deal with it
909Lisberr1:
910	clrw	%sp@			| re-clear pad word
911	tstl	_C_LABEL(nofault)	| catch bus error?
912	jeq	Lisberr			| no, handle as usual
913	movl	_C_LABEL(nofault),%sp@-	| yes,
914	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
915	/* NOTREACHED */
916#endif /* M68020 || M68030 */
917
918Lisberr:				| also used by M68040/60
919	movl	#T_BUSERR,%sp@-		| mark bus error
920	jra	_ASM_LABEL(faultstkadj)	| and deal with it
921
922/*
923 * FP exceptions.
924 */
925ENTRY_NOPROFILE(fpfline)
926#if defined(M68040)
927	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
928	jne	Lfp_unimp		| no, skip FPSP
929	cmpw	#0x202c,%sp@(6)		| format type 2?
930	jne	_C_LABEL(illinst)	| no, not an FP emulation
931#ifdef FPSP
932	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
933#else
934	clrl	%sp@-			| stack adjust count
935	moveml	#0xFFFF,%sp@-		| save registers
936	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
937	jra	_ASM_LABEL(fault)	| do it
938#endif
939Lfp_unimp:
940#endif /* M68040 */
941	jra	_C_LABEL(illinst)
942
943ENTRY_NOPROFILE(fpunsupp)
944#if defined(M68040)
945	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
946	jne	Lfp_unsupp		| No, skip FPSP
947#ifdef FPSP
948	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
949#else
950	clrl	%sp@-			| stack adjust count
951	moveml	#0xFFFF,%sp@-		| save registers
952	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
953	jra	_ASM_LABEL(fault)	| do it
954#endif
955Lfp_unsupp:
956#endif /* M68040 */
957	jra	_C_LABEL(illinst)
958
959/*
960 * Handles all other FP coprocessor exceptions.
961 * Note that since some FP exceptions generate mid-instruction frames
962 * and may cause signal delivery, we need to test for stack adjustment
963 * after the trap call.
964 */
965ENTRY_NOPROFILE(fpfault)
966	clrl	%sp@-		| stack adjust count
967	moveml	#0xFFFF,%sp@-	| save user registers
968	movl	%usp,%a0	| and save
969	movl	%a0,%sp@(FR_SP)	|   the user stack pointer
970	clrl	%sp@-		| no VA arg
971	movl	_C_LABEL(curpcb),%a0 | current pcb
972	lea	%a0@(PCB_FPCTX),%a0 | address of FP savearea
973	fsave	%a0@		| save state
974#if defined(M68040) || defined(M68060)
975	/* always null state frame on 68040, 68060 */
976	cmpl	#FPU_68040,_C_LABEL(fputype)
977	jle	Lfptnull
978#endif
979	tstb	%a0@		| null state frame?
980	jeq	Lfptnull	| yes, safe
981	clrw	%d0		| no, need to tweak BIU
982	movb	%a0@(1),%d0	| get frame size
983	bset	#3,%a0@(0,%d0:w) | set exc_pend bit of BIU
984Lfptnull:
985	fmovem	%fpsr,%sp@-	| push fpsr as code argument
986	frestore %a0@		| restore state
987	movl	#T_FPERR,%sp@-	| push type arg
988	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
989
990
991/*
992 * Other exceptions only cause four and six word stack frame and require
993 * no post-trap stack adjustment.
994 */
995
996ENTRY_NOPROFILE(badtrap)
997	moveml	#0xC0C0,%sp@-		| save scratch regs
998	movw	%sp@(22),%sp@-		| push exception vector info
999	clrw	%sp@-
1000	movl	%sp@(22),%sp@-		| and PC
1001	jbsr	_C_LABEL(straytrap)	| report
1002	addql	#8,%sp			| pop args
1003	moveml	%sp@+,#0x0303		| restore regs
1004	jra	_ASM_LABEL(rei)		| all done
1005
1006ENTRY_NOPROFILE(trap0)
1007	clrl	%sp@-			| stack adjust count
1008	moveml	#0xFFFF,%sp@-		| save user registers
1009	movl	%usp,%a0		| save the user SP
1010	movl	%a0,%sp@(FR_SP)		|   in the savearea
1011	movl	%d0,%sp@-		| push syscall number
1012	jbsr	_C_LABEL(syscall)	| handle it
1013	addql	#4,%sp			| pop syscall arg
1014	tstl	_C_LABEL(astpending)	| AST pending?
1015	jne	Lrei1			| Yup, go deal with it.
1016	movl	%sp@(FR_SP),%a0		| grab and restore
1017	movl	%a0,%usp		|   user SP
1018	moveml	%sp@+,#0x7FFF		| restore most registers
1019	addql	#8,%sp			| pop SP and stack adjust
1020	rte
1021
1022/*
1023 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
1024 *	cachectl(command, addr, length)
1025 * command in d0, addr in a1, length in d1
1026 */
1027ENTRY_NOPROFILE(trap12)
1028	movl	_C_LABEL(curlwp),%a0
1029	movl	%a0@(L_PROC),%sp@-	| push current proc pointer
1030	movl	%d1,%sp@-		| push length
1031	movl	%a1,%sp@-		| push addr
1032	movl	%d0,%sp@-		| push command
1033	jbsr	_C_LABEL(cachectl1)	| do it
1034	lea	%sp@(16),%sp		| pop args
1035	jra	_ASM_LABEL(rei)		| all done
1036
1037/*
1038 * Trace (single-step) trap.  Kernel-mode is special.
1039 * User mode traps are simply passed on to trap().
1040 */
1041ENTRY_NOPROFILE(trace)
1042	clrl	%sp@-			| stack adjust count
1043	moveml	#0xFFFF,%sp@-
1044	moveq	#T_TRACE,%d0
1045
1046	| Check PSW and see what happen.
1047	|   T=0 S=0	(should not happen)
1048	|   T=1 S=0	trace trap from user mode
1049	|   T=0 S=1	trace trap on a trap instruction
1050	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
1051
1052	movw	%sp@(FR_HW),%d1		| get PSW
1053	notw	%d1			| XXX no support for T0 on 680[234]0
1054	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
1055	jeq	Lkbrkpt			| yes, kernel breakpoint
1056	jra	_ASM_LABEL(fault)	| no, user-mode fault
1057
1058/*
1059 * Trap 15 is used for:
1060 *	- GDB breakpoints (in user programs)
1061 *	- KGDB breakpoints (in the kernel)
1062 *	- trace traps for SUN binaries (not fully supported yet)
1063 * User mode traps are simply passed to trap().
1064 */
1065ENTRY_NOPROFILE(trap15)
1066	clrl	%sp@-			| stack adjust count
1067	moveml	#0xFFFF,%sp@-
1068	moveq	#T_TRAP15,%d0
1069	movw	%sp@(FR_HW),%d1		| get PSW
1070	andw	#PSL_S,%d1		| from system mode?
1071	jne	Lkbrkpt			| yes, kernel breakpoint
1072	jra	_ASM_LABEL(fault)	| no, user-mode fault
1073
1074Lkbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type)
1075	| Save the system sp rather than the user sp.
1076	movw	#PSL_HIGHIPL,%sr	| lock out interrupts
1077	lea	%sp@(FR_SIZE),%a6	| Save stack pointer
1078	movl	%a6,%sp@(FR_SP)		|  from before trap
1079
1080	| If were are not on tmpstk switch to it.
1081	| (so debugger can change the stack pointer)
1082	movl	%a6,%d1
1083	cmpl	#_ASM_LABEL(tmpstk),%d1
1084	jls	Lbrkpt2			| already on tmpstk
1085	| Copy frame to the temporary stack
1086	movl	%sp,%a0			| a0=src
1087	lea	_ASM_LABEL(tmpstk)-96,%a1 | a1=dst
1088	movl	%a1,%sp			| sp=new frame
1089	movql	#FR_SIZE,%d1
1090Lbrkpt1:
1091	movl	%a0@+,%a1@+
1092	subql	#4,%d1
1093	jbgt	Lbrkpt1
1094
1095Lbrkpt2:
1096	| Call the trap handler for the kernel debugger.
1097	| Do not call trap() to do it, so that we can
1098	| set breakpoints in trap() if we want.  We know
1099	| the trap type is either T_TRACE or T_BREAKPOINT.
1100	| If we have both DDB and KGDB, let KGDB see it first,
1101	| because KGDB will just return 0 if not connected.
1102	| Save args in d2, a2
1103	movl	%d0,%d2			| trap type
1104	movl	%sp,%a2			| frame ptr
1105#ifdef KGDB
1106	| Let KGDB handle it (if connected)
1107	movl	%a2,%sp@-		| push frame ptr
1108	movl	%d2,%sp@-		| push trap type
1109	jbsr	_C_LABEL(kgdb_trap)	| handle the trap
1110	addql	#8,%sp			| pop args
1111	cmpl	#0,%d0			| did kgdb handle it?
1112	jne	Lbrkpt3			| yes, done
1113#endif
1114#ifdef DDB
1115	| Let DDB handle it
1116	movl	%a2,%sp@-		| push frame ptr
1117	movl	%d2,%sp@-		| push trap type
1118	jbsr	_C_LABEL(kdb_trap)	| handle the trap
1119	addql	#8,%sp			| pop args
1120#endif
1121	/* Sun 3 drops into PROM here. */
1122Lbrkpt3:
1123	| The stack pointer may have been modified, or
1124	| data below it modified (by kgdb push call),
1125	| so push the hardware frame at the current sp
1126	| before restoring registers and returning.
1127
1128	movl	%sp@(FR_SP),%a0		| modified sp
1129	lea	%sp@(FR_SIZE),%a1	| end of our frame
1130	movl	%a1@-,%a0@-		| copy 2 longs with
1131	movl	%a1@-,%a0@-		| ... predecrement
1132	movl	%a0,%sp@(FR_SP)		| sp = h/w frame
1133	moveml	%sp@+,#0x7FFF		| restore all but sp
1134	movl	%sp@,%sp		| ... and sp
1135	rte				| all done
1136
1137/*
1138 * Use common m68k sigreturn routine.
1139 */
1140#include <m68k/m68k/sigreturn.s>
1141
1142/*
1143 * Interrupt handlers.
1144 *
1145 * For auto-vectored interrupts, the CPU provides the
1146 * vector 0x18+level.
1147 *
1148 * intrhand_autovec is the entry point for auto-vectored
1149 * interrupts.
1150 *
1151 * For vectored interrupts, we pull the pc, evec, and exception frame
1152 * and pass them to the vectored interrupt dispatcher.  The vectored
1153 * interrupt dispatcher will deal with strays.
1154 *
1155 * intrhand_vectored is the entry point for vectored interrupts.
1156 */
1157
1158#define INTERRUPT_SAVEREG	moveml  #0xC0C0,%sp@-
1159#define INTERRUPT_RESTOREREG	moveml  %sp@+,#0x0303
1160
1161ENTRY_NOPROFILE(intrhand_autovec)
1162	addql	#1,_C_LABEL(interrupt_depth)
1163	INTERRUPT_SAVEREG
1164	lea	%sp@(16),%a1		| get pointer to frame
1165	movl	%a1,%sp@-
1166	jbsr	_C_LABEL(isrdispatch_autovec)  | call dispatcher
1167	addql	#4,%sp
1168	jbra	Lintrhand_exit
1169
1170ENTRY_NOPROFILE(intrhand_vectored)
1171	addql	#1,_C_LABEL(interrupt_depth)
1172	INTERRUPT_SAVEREG
1173	lea	%sp@(16),%a1		| get pointer to frame
1174	movl	%a1,%sp@-
1175	movw	%sr,%d0
1176	bfextu	%d0,21,3,%d0		| Get current ipl
1177	movl	%d0,%sp@-		| Push it
1178	jbsr	_C_LABEL(isrdispatch_vectored) | call dispatcher
1179	addql	#8,%sp
1180Lintrhand_exit:
1181	INTERRUPT_RESTOREREG
1182	subql	#1,_C_LABEL(interrupt_depth)
1183
1184	/* FALLTHROUGH to rei */
1185
1186#undef INTERRUPT_SAVEREG
1187#undef INTERRUPT_RESTOREREG
1188
1189/*
1190 * Emulation of VAX REI instruction.
1191 *
1192 * This code deals with checking for and servicing ASTs
1193 * (profiling, scheduling).
1194 * After identifing that we need an AST we drop the IPL to allow device
1195 * interrupts.
1196 *
1197 * This code is complicated by the fact that sendsig may have been called
1198 * necessitating a stack cleanup.
1199 */
1200ASENTRY_NOPROFILE(rei)
1201	tstl	_C_LABEL(astpending)	| AST pending?
1202	jeq	Ldorte			| Nope. Just return.
1203	btst	#5,%sp@			| Returning to kernel mode?
1204	jne	Ldorte			| Yup. Can't do ASTs
1205	movw	#PSL_LOWIPL,%sr		| lower SPL
1206	clrl	%sp@-			| stack adjust
1207	moveml	#0xFFFF,%sp@-		| save all registers
1208	movl	%usp,%a1		| including
1209	movl	%a1,%sp@(FR_SP)		|    the users SP
1210Lrei1:	clrl	%sp@-			| VA == none
1211	clrl	%sp@-			| code == none
1212	movl	#T_ASTFLT,%sp@-		| type == async system trap
1213	pea	%sp@(12)		| fp == address of trap frame
1214	jbsr	_C_LABEL(trap)		| go handle it
1215	lea	%sp@(16),%sp		| pop value args
1216	movl	%sp@(FR_SP),%a0		| restore user SP
1217	movl	%a0,%usp		|   from save area
1218	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
1219	jne	Laststkadj		| yes, go to it
1220	moveml	%sp@+,#0x7FFF		| no, restore most user regs
1221	addql	#8,%sp			| toss SP and stack adjust
1222Ldorte:	rte				| and do real RTE
1223
1224Laststkadj:
1225	lea	%sp@(FR_HW),%a1		| pointer to HW frame
1226	addql	#8,%a1			| source pointer
1227	movl	%a1,%a0			| source
1228	addw	%d0,%a0			|  + hole size = dest pointer
1229	movl	%a1@-,%a0@-		| copy
1230	movl	%a1@-,%a0@-		|  8 bytes
1231	movl	%a0,%sp@(FR_SP)		| new SSP
1232	moveml	%sp@+,#0x7FFF		| restore user registers
1233	movl	%sp@,%sp		| and our SP
1234	rte				| and do real RTE
1235
1236/*
1237 * Use common m68k sigcode.
1238 */
1239#include <m68k/m68k/sigcode.s>
1240#ifdef COMPAT_SUNOS
1241#include <m68k/m68k/sunos_sigcode.s>
1242#endif
1243#ifdef COMPAT_SVR4
1244#include <m68k/m68k/svr4_sigcode.s>
1245#endif
1246
1247/*
1248 * Primitives
1249 */
1250
1251/*
1252 * Use common m68k support routines.
1253 */
1254#include <m68k/m68k/support.s>
1255
1256/*
1257 * Use common m68k process/lwp switch and context save subroutines.
1258 */
1259#define	FPCOPROC	/* XXX: Temp. Reqd. */
1260#include <m68k/m68k/switch_subr.s>
1261
1262
1263#if defined(M68040) || defined(M68060)
1264ENTRY(suline)
1265	movl	%sp@(4),%a0		| address to write
1266	movl	_C_LABEL(curpcb),%a1	| current pcb
1267	movl	#Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault
1268	movl	%sp@(8),%a1		| address of line
1269	movl	%a1@+,%d0		| get lword
1270	movsl	%d0,%a0@+		| put lword
1271	nop				| sync
1272	movl	%a1@+,%d0		| get lword
1273	movsl	%d0,%a0@+		| put lword
1274	nop				| sync
1275	movl	%a1@+,%d0		| get lword
1276	movsl	%d0,%a0@+		| put lword
1277	nop				| sync
1278	movl	%a1@+,%d0		| get lword
1279	movsl	%d0,%a0@+		| put lword
1280	nop				| sync
1281	moveq	#0,%d0			| indicate no fault
1282	jra	Lsldone
1283Lslerr:
1284	moveq	#-1,%d0
1285Lsldone:
1286	movl	_C_LABEL(curpcb),%a1	| current pcb
1287	clrl	%a1@(PCB_ONFAULT)	| clear fault address
1288	rts
1289#endif
1290
1291
1292ENTRY(ecacheon)
1293	rts
1294
1295ENTRY(ecacheoff)
1296	rts
1297
1298/*
1299 * Get callers current SP value.
1300 * Note that simply taking the address of a local variable in a C function
1301 * doesn't work because callee saved registers may be outside the stack frame
1302 * defined by A6 (e.g. GCC generated code).
1303 */
1304ENTRY_NOPROFILE(getsp)
1305	movl	%sp,%d0			| get current SP
1306	addql	#4,%d0			| compensate for return address
1307	movl	%d0,%a0
1308	rts
1309
1310ENTRY_NOPROFILE(getsfc)
1311	movc	%sfc,%d0
1312	movl	%d0,%a0
1313	rts
1314
1315ENTRY_NOPROFILE(getdfc)
1316	movc	%dfc,%d0
1317	movl	%d0,%a0
1318	rts
1319
1320/*
1321 * Load a new user segment table pointer.
1322 */
1323ENTRY(loadustp)
1324	movl	%sp@(4),%d0		| new USTP
1325	moveq	#PGSHIFT, %d1
1326	lsll	%d1,%d0			| convert to addr
1327#if defined(M68040) || defined(M68060)
1328	cmpl    #MMU_68040,_C_LABEL(mmutype) | 68040?
1329	jne     LmotommuC               | no, skip
1330	.word	0xf518			| pflusha
1331	.long   0x4e7b0806              | movc d0,urp
1332#ifdef M68060
1333	cmpl	#CPU_68060,_C_LABEL(cputype)
1334	jne	Lldno60
1335	movc	%cacr,%d0
1336	orl	#IC60_CUBC,%d0		| clear user branch cache entries
1337	movc	%d0,%cacr
1338Lldno60:
1339#endif
1340	rts
1341LmotommuC:
1342#endif
1343	pflusha				| flush entire TLB
1344	lea	_C_LABEL(protorp),%a0	| CRP prototype
1345	movl	%d0,%a0@(4)		| stash USTP
1346	pmove	%a0@,%crp		| load root pointer
1347	movl	#CACHE_CLR,%d0
1348	movc	%d0,%cacr		| invalidate cache(s)
1349	rts
1350
1351ENTRY(ploadw)
1352#ifdef M68030
1353#if defined(M68040) || defined(M68060)
1354	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1355	jeq	Lploadwskp		| yes, skip
1356#endif
1357	movl	%sp@(4),%a0		| address to load
1358	ploadw	#1,%a0@			| pre-load translation
1359Lploadwskp:
1360#endif
1361	rts
1362
1363ENTRY(getsr)
1364	moveq	#0,%d0
1365	movw	%sr,%d0
1366	rts
1367
1368/*
1369 * _delay(unsigned N)
1370 *
1371 * Delay for at least (N/1024) microseconds.
1372 * This routine depends on the variable:  delay_divisor
1373 * which should be set based on the CPU clock rate.
1374 */
1375ENTRY_NOPROFILE(_delay)
1376	| d0 = arg = (usecs << 10)
1377	movl	%sp@(4),%d0
1378	| d1 = delay_divisor
1379	movl	_C_LABEL(delay_divisor),%d1
1380	jra	L_delay			/* Jump into the loop! */
1381
1382	/*
1383	 * Align the branch target of the loop to a half-line (8-byte)
1384	 * boundary to minimize cache effects.  This guarantees both
1385	 * that there will be no prefetch stalls due to cache line burst
1386	 * operations and that the loop will run from a single cache
1387	 * half-line.
1388	 */
1389#ifdef __ELF__
1390	.align	8
1391#else
1392	.align	3
1393#endif
1394L_delay:
1395	subl	%d1,%d0
1396	jgt	L_delay
1397	rts
1398
1399/*
1400 * Save and restore 68881 state.
1401 */
1402ENTRY(m68881_save)
1403	movl	%sp@(4),%a0		| save area pointer
1404	fsave	%a0@			| save state
1405#if defined(M68020) || defined(M68030) || defined(M68040)
1406#if defined(M68060)
1407	cmpl	#FPU_68060,_C_LABEL(fputype)
1408	jeq	Lm68060fpsave
1409#endif
1410Lm68881fpsave:
1411	tstb	%a0@			| null state frame?
1412	jeq	Lm68881sdone		| yes, all done
1413	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
1414	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers
1415Lm68881sdone:
1416	rts
1417#endif
1418#if defined(M68060)
1419Lm68060fpsave:
1420	tstb	%a0@(2)			| null state frame?
1421	jeq	Lm68060sdone		| yes, all done
1422	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
1423	fmovem	%fpcr,%a0@(FPF_FPCR)	| save FP control registers
1424	fmovem	%fpsr,%a0@(FPF_FPSR)
1425	fmovem	%fpi,%a0@(FPF_FPI)
1426Lm68060sdone:
1427        rts
1428#endif
1429
1430ENTRY(m68881_restore)
1431	movl	%sp@(4),%a0		| save area pointer
1432#if defined(M68020) || defined(M68030) || defined(M68040)
1433#if defined(M68060)
1434	cmpl	#FPU_68060,_C_LABEL(fputype)
1435	jeq	Lm68060fprestore
1436#endif
1437Lm68881fprestore:
1438	tstb	%a0@			| null state frame?
1439	jeq	Lm68881rdone		| yes, easy
1440	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers
1441	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general registers
1442Lm68881rdone:
1443	frestore %a0@			| restore state
1444	rts
1445#endif
1446#if defined(M68060)
1447Lm68060fprestore:
1448	tstb	%a0@(2)			| null state frame?
1449	jeq	Lm68060fprdone		| yes, easy
1450	fmovem	%a0@(FPF_FPCR),%fpcr	| restore FP control registers
1451	fmovem	%a0@(FPF_FPSR),%fpsr
1452	fmovem	%a0@(FPF_FPI),%fpi
1453	fmovem	%a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers
1454Lm68060fprdone:
1455	frestore %a0@			| restore state
1456	rts
1457#endif
1458
1459/*
1460 * Handle the nitty-gritty of rebooting the machine.
1461 * Basically we just turn off the MMU, restore the Bug's initial VBR
1462 * and either return to Bug or jump through the ROM reset vector
1463 * depending on how the system was halted.
1464 */
1465ENTRY_NOPROFILE(doboot)
1466	movw	#PSL_HIGHIPL,%sr
1467	movl	_C_LABEL(boothowto),%d1	| load howto
1468	movl	%sp@(4),%d2		| arg
1469	movl	_ASM_LABEL(bug_vbr),%d3	| Fetch Bug's original VBR value
1470	movl	_C_LABEL(machineid),%d4	| What type of board is this?
1471	movl	#CACHE_OFF,%d0
1472#if defined(M68040) || defined(M68060)
1473	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040/68060?
1474	jne	Lnocache0		| no, skip
1475	.word	0xf4f8			| cpusha bc - push and invalidate caches
1476	nop
1477	movl	#CACHE40_OFF,%d0
1478#endif
1479Lnocache0:
1480	movc	%d0,%cacr		| disable on-chip cache(s)
1481
1482#if defined(M68040) || defined(M68060)
1483	cmpl	#MMU_68040,_C_LABEL(mmutype)
1484	jne	LmotommuF
1485	movql	#0,%d0
1486	movc	%d0,%cacr
1487	.long	0x4e7b0003              | movc d0,tc
1488	jra	Lbootcommon
1489LmotommuF:
1490#endif
1491	clrl	%sp@-			| value for pmove to TC (turn off MMU)
1492	pmove	%sp@,%tc		| disable MMU
1493	addql	#4,%sp
1494
1495Lbootcommon:
1496	/*
1497	 * MMU Switched off by now, so relocate all absolute references
1498	 */
1499	ASRELOC(tmpstk, %sp)		| physical SP in case of NMI
1500	movc	%d3,%vbr		| Restore Bug's VBR
1501	andl	#RB_SBOOT, %d1		| mask off
1502	jbne	Lsboot			| sboot?
1503	/* NOT sboot */
1504	tstl	%d2			| autoboot?
1505	jbeq	Ldoreset		| yes!
1506	CALLBUG(MVMEPROM_EXIT)		| return to bug
1507	/* NOTREACHED */
1508
1509Ldoreset:
1510	movl	#0xff800000,%a0		| Bug's reset vector address
1511	movl	%a0@+, %a7		| get SP
1512	movl	%a0@, %a0		| get PC
1513	jmp	%a0@			| go!
1514
1515Lsboot: /* sboot */
1516	tstl	%d2			| autoboot?
1517	jbeq	1f			| yes!
1518	jmp 	0x4000			| back to sboot
15191:	jmp	0x400a			| tell sboot to reboot us
1520
1521
1522/*
1523 * Misc. global variables.
1524 */
1525	.data
1526
1527GLOBAL(machineid)
1528	.long	MVME_147	| default to MVME_147
1529
1530GLOBAL(mmutype)
1531	.long	MMU_68030	| default to MMU_68030
1532
1533GLOBAL(cputype)
1534	.long	CPU_68030	| default to CPU_68030
1535
1536GLOBAL(fputype)
1537	.long	FPU_68882	| default to FPU_68882
1538
1539GLOBAL(protorp)
1540	.long	0,0		| prototype root pointer
1541
1542/*
1543 * Information from first stage boot program
1544 */
1545GLOBAL(bootpart)
1546	.long	0
1547GLOBAL(bootdevlun)
1548	.long	0
1549GLOBAL(bootctrllun)
1550	.long	0
1551GLOBAL(bootaddr)
1552	.long	0
1553
1554GLOBAL(proc0paddr)
1555	.long	0		| KVA of proc0 u-area
1556
1557GLOBAL(intiobase)
1558	.long	0		| KVA of base of internal IO space
1559
1560GLOBAL(intiolimit)
1561	.long	0		| KVA of end of internal IO space
1562
1563GLOBAL(intiobase_phys)
1564	.long	0		| PA of board's I/O registers
1565
1566GLOBAL(intiotop_phys)
1567	.long	0		| PA of top of board's I/O registers
1568
1569/*
1570 * interrupt counters.
1571 * XXXSCW: Will go away soon; kept here to keep vmstat happy
1572 */
1573GLOBAL(intrnames)
1574	.asciz	"spur"
1575	.asciz	"lev1"
1576	.asciz	"lev2"
1577	.asciz	"lev3"
1578	.asciz	"lev4"
1579	.asciz	"clock"
1580	.asciz	"lev6"
1581	.asciz	"nmi"
1582	.asciz	"statclock"
1583GLOBAL(eintrnames)
1584	.even
1585
1586GLOBAL(intrcnt)
1587	.long	0,0,0,0,0,0,0,0,0,0
1588GLOBAL(eintrcnt)
1589