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