xref: /netbsd-src/sys/arch/mvme68k/mvme68k/locore.s (revision a542b07802ade0397725fd0b67be83b8b79eb446)
1/*	$NetBSD: locore.s,v 1.131 2024/01/18 05:12:30 thorpej 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_sunos.h"
43#include "opt_fpsp.h"
44#include "opt_ddb.h"
45#include "opt_kgdb.h"
46#include "opt_lockdebug.h"
47#include "opt_m68k_arch.h"
48#include "opt_mvmeconf.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
66/*
67 * Macro to relocate a symbol, used before MMU is enabled.
68 */
69#define	_RELOC(var, ar)		\
70	lea	var,ar
71
72#define	RELOC(var, ar)		_RELOC(_C_LABEL(var), ar)
73#define	ASRELOC(var, ar)	_RELOC(_ASM_LABEL(var), ar)
74
75/*
76 * Macro to call into the Bug ROM monitor
77 */
78#define	CALLBUG(func)	\
79	trap #15; .short func
80
81/*
82 * Initialization
83 *
84 * The bootstrap loader loads us in starting at 0, and VBR is non-zero.
85 * On entry, args on stack are boot device, boot filename, console unit,
86 * boot flags (howto), boot device name, filesystem type name.
87 */
88BSS(lowram,4)
89BSS(esym,4)
90
91	.globl	_C_LABEL(edata)
92	.globl	_C_LABEL(etext),_C_LABEL(end)
93
94
95/*
96 * This is for kvm_mkdb, and should be the address of the beginning
97 * of the kernel text segment (not necessarily the same as kernbase).
98 */
99	.text
100GLOBAL(kernel_text)
101
102/*
103 * start of kernel and .text!
104 */
105ASENTRY_NOPROFILE(start)
106	movw	#PSL_HIGHIPL,%sr	| no interrupts
107	movl	#0,%a5			| RAM starts at 0 (a5)
108	movl	%sp@(4), %d7		| get boothowto
109	movl	%sp@(8), %d6		| get bootaddr
110	movl	%sp@(12),%d5		| get bootctrllun
111	movl	%sp@(16),%d4		| get bootdevlun
112	movl	%sp@(20),%d3		| get bootpart
113	movl	%sp@(24),%d2		| get esyms
114
115	RELOC(bootpart,%a0)
116	movl	%d3, %a0@		| save bootpart
117	RELOC(bootdevlun,%a0)
118	movl	%d4, %a0@		| save bootdevlun
119	RELOC(bootctrllun,%a0)
120	movl	%d5, %a0@		| save booctrllun
121	RELOC(bootaddr,%a0)
122	movl	%d6, %a0@		| save bootaddr
123	RELOC(boothowto,%a0)
124	movl	%d7, %a0@		| save boothowto
125	/* note: d3-d7 free, d2 still in use */
126
127	ASRELOC(tmpstk, %a0)
128	movl	%a0,%sp			| give ourselves a temporary stack
129
130	RELOC(edata,%a0)		| clear out BSS
131	movl	#_C_LABEL(end) - 4, %d0	| (must be <= 256 kB)
132	subl	#_C_LABEL(edata), %d0
133	lsrl	#2,%d0
1341:	clrl	%a0@+
135	dbra	%d0,1b
136
137	RELOC(esym, %a0)
138	movl	%d2,%a0@		| store end of symbol table
139	/* d2 now free */
140	RELOC(lowram, %a0)
141	movl	%a5,%a0@		| store start of physical memory
142	movl	#CACHE_OFF,%d0
143	movc	%d0,%cacr		| clear and disable on-chip cache(s)
144
145	/* ask the Bug what we are... */
146	clrl	%sp@-
147	CALLBUG(MVMEPROM_GETBRDID)
148	movl	%sp@+,%a1
149
150	/* copy to a struct mvmeprom_brdid */
151	movl	#MVMEPROM_BRDID_SIZE,%d0
152	RELOC(boardid,%a0)
1531:	movb	%a1@+,%a0@+
154	subql	#1,%d0
155	jbne	1b
156
157	/*
158	 * Grab the model number from _boardid and use the value
159	 * to setup machineid, cputype, and mmutype.
160	 */
161	clrl	%d0
162	RELOC(boardid,%a1)
163	movw	%a1@(MVMEPROM_BRDID_MODEL_OFFSET),%d0
164	RELOC(machineid,%a0)
165	movl	%d0,%a0@
166
167	ASRELOC(Lbrdid2mach,%a0)
168Lbrdmatch:
169	cmpw	%a0@+,%d0
170	jbeq	Lgotmatch
171	addw	#0x12,%a0		| Each entry is 20-2 bytes long
172	tstw	%a0@
173	jbne	Lbrdmatch
174
175	/*
176	 * If we fall to here, the board is not supported.
177	 * Print a warning, then drop out to the Bug.
178	 */
179	movl	#Lenotconf,%sp@-
180	movl	#Lnotconf,%sp@-
181	CALLBUG(MVMEPROM_OUTSTRCRLF)
182	addql	#8,%sp			| clean up stack after call
183
184	CALLBUG(MVMEPROM_EXIT)
185	/* NOTREACHED */
186
187	.data
188Lnotconf:
189	.ascii	"Sorry, the kernel isn't configured for this model."
190Lenotconf:
191	.even
192
193ASLOCAL(Lbrdid2mach)
194#ifdef MVME147
195	.word	MVME_147
196	.word		CPU_68030
197	.word		MMU_68030
198	.word		FPU_68882
199	.long		Linit147
200#endif
201#ifdef MVME162
202	.word	MVME_162
203	.word		CPU_68040
204	.word		MMU_68040
205	.word		FPU_68040
206	.long		Linit1x2
207#endif
208#ifdef MVME167
209	.word	MVME_167
210	.word		CPU_68040
211	.word		MMU_68040
212	.word		FPU_68040
213	.long		Linit1x7
214#endif
215#ifdef MVME172
216	.word	MVME_172
217	.word		CPU_68060
218	.word		MMU_68040
219	.word		FPU_68060
220	.long		Linit1x2
221#endif
222#ifdef MVME177
223	.word	MVME_177
224	.word		CPU_68060
225	.word		MMU_68040
226	.word		FPU_68060
227	.long		Linit1x7
228#endif
229	.word	0
230	.text
231	.even
232
233/*
234 * We have a match, so the kernel should support this board.
235 * a0 points to the matching entry in Lbrdid2mach.
236 */
237Lgotmatch:
238	movew	%a0@+,%d1		| Copy the CPU type
239	extl	%d1
240	RELOC(cputype,%a1)
241	movel	%d1,%a1@
242
243	movew	%a0@+,%d1		| Copy the MMU type
244	extl	%d1
245	RELOC(mmutype,%a1)
246	movel	%d1,%a1@
247
248	movew	%a0@+,%d1		| Copy the FPU type
249	extl	%d1
250	RELOC(fputype,%a1)
251	movel	%d1,%a1@
252
253	movel	%a0@,%a0		| Finally, the board-specific init code
254	jmp	%a0@
255
256
257#ifdef MVME147
258Linit147:
259	/* MVME-147 - 68030 CPU/MMU, 68882 FPU */
260	/* XXXCDC SHUTUP 147 CALL */
261	movb	#0, 0xfffe1026		| serial interrupt off
262	movb	#0, 0xfffe1018		| timer 1 off
263	movb	#0, 0xfffe1028		| ethernet off
264	/* XXXCDC SHUTUP 147 CALL */
265
266	/* Save our ethernet address */
267	RELOC(mvme_ea, %a0)
268	lea	0xfffe0778,%a1		| XXXCDC -- HARDWIRED HEX
269	movb	#0x08,%a0@+
270	clrb	%a0@+
271	movb	#0x3e,%a0@+
272	movql	#0x0f,%d0
273	andb	%a1@+,%d0
274	orb	#0x20,%d0
275	movb	%d0,%a0@+
276	movb	%a1@+,%a0@+
277	movb	%a1@,%a0@
278
279	/*
280	 * Fix up the physical addresses of the MVME147's onboard
281	 * I/O registers.
282	 */
283	RELOC(intiobase_phys, %a0);
284	movl	#INTIOBASE147,%a0@
285	RELOC(intiotop_phys, %a0);
286	movl	#INTIOTOP147,%a0@
287
288	/* initialise list of physical memory segments for pmap_bootstrap */
289	RELOC(phys_seg_list, %a0)
290	movl	%a5,%a0@		| phys_seg_list[0].ps_start
291	movl	0xfffe0774,%d1		| End + 1 of onboard memory
292	movl	%d1,%a0@(4)		| phys_seg_list[0].ps_end
293	clrl	%a0@(8)			| phys_seg_list[0].ps_startpage
294
295	/* offboard RAM */
296	clrl	%a0@(0x0c)		| phys_seg_list[1].ps_start
297	movl	#PAGE_SIZE-1,%d0
298	addl	0xfffe0764,%d0		| Start of offboard segment
299	andl	#-PAGE_SIZE,%d0		| Round up to page boundary
300	jbeq	Lsavmaxmem		| Jump if none defined
301	movl	#PAGE_SIZE,%d1		| Note: implicit '+1'
302	addl	0xfffe0768,%d1		| End of offboard segment
303	andl	#-PAGE_SIZE,%d1		| Round up to page boundary
304	cmpl	%d1,%d0			| Quick and dirty validity check
305	jbcs	Loff_ok			| Yup, looks good.
306	movel	%a0@(4),%d1		| Just use onboard RAM otherwise
307	jbra	Lsavmaxmem
308Loff_ok:
309	movl	%d0,%a0@(0x0c)		| phys_seg_list[1].ps_start
310	movl	%d1,%a0@(0x10)		| phys_seg_list[1].ps_end
311	clrl	%a0@(0x14)		| phys_seg_list[1].ps_startpage
312
313	/*
314	 * Offboard RAM needs to be cleared to zero to initialise parity
315	 * on most VMEbus RAM cards. Without this, some cards will buserr
316	 * when first read.
317	 */
318	movel	%d0,%a0			| offboard start address again.
319Lclearoff:
320	clrl	%a0@+			| zap a word
321	cmpl	%a0,%d1			| reached end?
322	jbne	Lclearoff
323
324Lsavmaxmem:
325	moveq	#PGSHIFT,%d2
326	lsrl	%d2,%d1			| convert to page (click) number
327	RELOC(maxmem, %a0)
328	movl	%d1,%a0@		| save as maxmem
329	jra	Lstart1
330#endif
331
332#if defined(MVME162) || defined(MVME172)
333Linit1x2:
334	/* MVME-162 - 68040 CPU/MMU/FPU */
335	/* MVME-172 - 68060 CPU/MMU/FPU */
336
337	/*
338	 * Verify the user has removed the GPIO#0 jumper...
339	 */
340	btst	#0,0xfff4202d		| Clear == jumper installed
341	jne	1f			| Ok.
342
343	movl	#Le1x2jump,%sp@-
344	movl	#L1x2jump,%sp@-
345	CALLBUG(MVMEPROM_OUTSTRCRLF)
346	addql	#8,%sp			| clean up stack after call
347
348	CALLBUG(MVMEPROM_EXIT)
349	/* NOTREACHED */
350
3511:
352	/*
353	 * Determine if this board has a VMEchip2
354	 */
355	btst	#1,0xfff4202e		| VMEchip2 presence detect
356	jne	2f			| Jump if it doesn't exist.
357
358	/*
359	 * Disable all interrupts from VMEchip2. This is especially
360	 * useful when the kernel doesn't have the VMEchip2 driver
361	 * configured. If we didn't do this, then we're at the mercy
362	 * of whatever VMEchip2 interrupts the ROM set up. For example,
363	 * hitting the ABORT switch could kill the system...
364	 */
365	movl	0xfff40088,%d0
366	andl	#0xff7fffff,%d0		| Clear 'MIEN'
367	movl	%d0,0xfff40088
3682:
369	/*
370	 * Determine how much onboard memory is installed
371	 */
372	movql	#0x07,%d0
373	andb	0xfff42024,%d0
374	ASRELOC(Ldramsize1x2,%a0)
375	movl	%a0@(%d0:w:4),%d1	| Lookup the size
376	jeq	Lmemcquery		| Assume a MEMC chip if this is zero.
377	jra	Lis1xx_common
378
379	.data
380	.even
381	/*
382	 * Table of DRAM register size values -> actual size in bytes
383	 */
384ASLOCAL(Ldramsize1x2)
385	.long	0x00100000
386	.long	0x00200000
387	.long	0x00000000
388	.long	0x00400000
389	.long	0x00400000
390	.long	0x00800000
391	.long	0x00000000
392	.long	0x01000000
393
394L1x2jump:
395	.ascii	"You must remove the jumper from pins 15-16 of J22 (mvme162)"
396	.ascii	"or pins 1-2\015\012"
397	.ascii	"J11 (mvme162-LX) first! See NetBSD/mvme68k FAQ for details."
398Le1x2jump:
399	.even
400
401	.text
402#endif
403
404#if defined(MVME167) || defined(MVME177)
405Linit1x7:
406	/* MVME-167 - 68040 CPU/MMU/FPU */
407	/* MVME-177 - 68060 CPU/MMU/FPU */
408
409	/*
410	 * Verify the user has removed the GPIO#0 jumper...
411	 */
412	movel	#0x00000001,%d0
413	andl	0xfff40088,%d0		| Clear == jumper installed
414	jne	1f			| Ok.
415
416	movl	#Le1x7jump,%sp@-
417	movl	#L1x7jump,%sp@-
418	CALLBUG(MVMEPROM_OUTSTRCRLF)
419	addql	#8,%sp			| clean up stack after call
420
421	CALLBUG(MVMEPROM_EXIT)
422	/* NOTREACHED */
423
4241:
425	/*
426	 * Disable all interrupts from VMEchip2. This is especially
427	 * useful when the kernel doesn't have the VMEchip2 driver
428	 * configured. If we didn't do this, then we're at the mercy
429	 * of whatever VMEchip2 interrupts the ROM set up. For example,
430	 * hitting the ABORT switch could kill the system...
431	 */
432	movl	0xfff40088,%d0
433	andl	#0xff7fffff,%d0		| Clear 'MIEN'
434	movl	%d0,0xfff40088
435
436	.data
437	.even
438L1x7jump:
439	.ascii	"You must remove the jumper from pins 1-2 of J1!\015\012"
440	.ascii	"See NetBSD/mvme68k FAQ for details."
441Le1x7jump:
442	.even
443
444	.text
445#endif
446
447#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
448Lmemcquery:
449	/*
450	 * Figure out the size of onboard DRAM by querying
451	 * the memory controller ASIC(s)
452	 */
453	lea	0xfff43008,%a0		| MEMC040/MEMECC Controller #1
454	jbsr	memc040read
455	movl	%d0,%d1
456
457	lea	0xfff43108,%a0		| MEMC040/MEMECC Controller #2
458	jbsr	memc040read
459	addl	%d0,%d1
460
461Lis1xx_common:
462	/* Save our ethernet address */
463	RELOC(mvme_ea, %a0)
464	lea	0xfffc1f2c,%a1
465	movb	%a1@+,%a0@+
466	movb	%a1@+,%a0@+
467	movb	%a1@+,%a0@+
468	movb	%a1@+,%a0@+
469	movb	%a1@+,%a0@+
470	movb	%a1@,%a0@
471
472	/*
473	 * Fix up the physical addresses of the onboard
474	 * I/O registers.
475	 */
476	RELOC(intiobase_phys, %a0);
477	movl	#INTIOBASE1xx,%a0@
478	RELOC(intiotop_phys, %a0);
479	movl	#INTIOTOP1xx,%a0@
480
481	/*
482	 * Initialise first physical memory segment with onboard RAM details
483	 */
484	RELOC(phys_seg_list, %a0)
485	movl	%a5,%a0@		| phys_seg_list[0].ps_start
486	movl	%d1,%a0@(4)		| phys_seg_list[0].ps_end
487	clrl	%a0@(8)			| phys_seg_list[0].ps_startpage
488
489	/* offboard RAM */
490	clrl	%a0@(0x0c)		| phys_seg_list[1].ps_start
491	movl	#PAGE_SIZE-1,%d0
492	addl	0xfffc0000,%d0		| Start of offboard segment
493	andl	#-PAGE_SIZE,%d0		| Round up to page boundary
494	jbeq	Ldone1xx		| Jump if none defined
495	movl	#PAGE_SIZE,%d1		| Note: implicit '+1'
496	addl	0xfffc0004,%d1		| End of offboard segment
497	andl	#-PAGE_SIZE,%d1		| Round up to page boundary
498	cmpl	%d1,%d0			| Quick and dirty validity check
499	jbcs	Lramsave1xx		| Yup, looks good.
500	movel	%a0@(4),%d1		| Just use onboard RAM otherwise
501	jbra	Ldone1xx
502
503Lramsave1xx:
504	movl	%d0,%a0@(0x0c)		| phys_seg_list[1].ps_start
505	movl	%d1,%a0@(0x10)		| phys_seg_list[1].ps_end
506	clrl	%a0@(0x14)		| phys_seg_list[1].ps_startpage
507
508	/*
509	 * Offboard RAM needs to be cleared to zero to initialise parity
510	 * on most VMEbus RAM cards. Without this, some cards will buserr
511	 * when first read.
512	 */
513	movel	%d0,%a0			| offboard start address again.
514Lramclr1xx:
515	clrl	%a0@+			| zap a word
516	cmpl	%a0,%d1			| reached end?
517	jbne	Lramclr1xx
518
519Ldone1xx:
520	moveq	#PGSHIFT,%d2
521	lsrl	%d2,%d1			| convert to page (click) number
522	RELOC(maxmem, %a0)
523	movl	%d1,%a0@		| save as maxmem
524
525	/* FALLTHROUGH to Lstart1 */
526#endif
527
528
529Lstart1:
530/* initialize source/destination control registers for movs */
531	moveq	#FC_USERD,%d0		| user space
532	movc	%d0,%sfc		|   as source
533	movc	%d0,%dfc		|   and destination of transfers
534/*
535 * configure kernel and lwp0 VA space so we can get going
536 */
537#if NKSYMS || defined(DDB) || defined(MODULAR)
538	RELOC(esym,%a0)			| end of static kernel text/data syms
539	movl	%a0@,%d2
540	jne	Lstart2
541#endif
542	movl	#_C_LABEL(end),%d2	| end of static kernel text/data
543Lstart2:
544	addl	#PAGE_SIZE-1,%d2
545	andl	#PG_FRAME,%d2		| round to a page
546	movl	%d2,%a4
547	addl	%a5,%a4			| convert to PA
548	pea	%a5@			| firstpa
549	pea	%a4@			| nextpa
550	RELOC(pmap_bootstrap,%a0)
551	jbsr	%a0@			| pmap_bootstrap(firstpa, nextpa)
552	addql	#8,%sp
553
554/*
555 * Enable the MMU.
556 * Since the kernel is mapped logical == physical, we just turn it on.
557 */
558	RELOC(Sysseg_pa, %a0)		| system segment table addr
559	movl	%a0@,%d1		| read value (a PA)
560	RELOC(mmutype, %a0)
561	cmpl	#MMU_68040,%a0@		| 68040?
562	jne	Lmotommu1		| no, skip
563	.long	0x4e7b1807		| movc d1,srp
564	jra	Lstploaddone
565Lmotommu1:
566#ifdef M68030
567	RELOC(protorp, %a0)
568	movl	%d1,%a0@(4)		| segtable address
569	pmove	%a0@,%srp		| load the supervisor root pointer
570#endif /* M68030 */
571Lstploaddone:
572	RELOC(mmutype, %a0)
573	cmpl	#MMU_68040,%a0@		| 68040?
574	jne	Lmotommu2		| no, skip
575	moveq	#0,%d0			| ensure TT regs are disabled
576	.long	0x4e7b0004		| movc d0,itt0
577	.long	0x4e7b0005		| movc d0,itt1
578	.long	0x4e7b0006		| movc d0,dtt0
579	.long	0x4e7b0007		| movc d0,dtt1
580	.word	0xf4d8			| cinva bc
581	.word	0xf518			| pflusha
582	movl	#0x8000,%d0
583	.long	0x4e7b0003		| movc d0,tc
584#ifdef M68060
585	RELOC(cputype, %a0)
586	cmpl	#CPU_68060,%a0@		| 68060?
587	jne	Lnot060cache
588	movl	#1,%d0
589	.long	0x4e7b0808		| movcl d0,pcr
590	movl	#0xa0808000,%d0
591	movc	%d0,%cacr		| enable store buffer, both caches
592	jmp	Lenab1
593Lnot060cache:
594#endif
595	movl	#0x80008000,%d0
596	movc	%d0,%cacr		| turn on both caches
597	jmp	Lenab1
598Lmotommu2:
599	pflusha
600	movl	#MMU51_TCR_BITS,%sp@-	| value to load TC with
601	pmove	%sp@,%tc		| load it
602
603/*
604 * Should be running mapped from this point on
605 */
606Lenab1:
607/* Point the CPU VBR at our vector table */
608	lea	_ASM_LABEL(tmpstk),%sp	| re-load temporary stack
609	jbsr	_C_LABEL(vec_init)	| initialize vector table
610/* call final pmap setup */
611	jbsr	_C_LABEL(pmap_bootstrap_finalize)
612/* set kernel stack, user SP */
613	movl	_C_LABEL(lwp0uarea),%a1	| get lwp0 uarea
614	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
615	movl	#USRSTACK-4,%a2
616	movl	%a2,%usp		| init user SP
617	tstl	_C_LABEL(fputype)	| Have an FPU?
618	jeq	Lenab2			| No, skip.
619	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
620	movl	%a1,%sp@-
621	jbsr	_C_LABEL(m68881_restore) | restore it (does not kill a1)
622	addql	#4,%sp
623Lenab2:
624	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
625	jeq	Ltbia040		| yes, cache already on
626	pflusha
627	movl	#CACHE_ON,%d0
628	movc	%d0,%cacr		| clear cache(s)
629	jra	Lenab3
630Ltbia040:
631	.word	0xf518
632Lenab3:
633/*
634 * final setup for C code:
635 * Create a fake exception frame so that cpu_lwp_fork() can copy it.
636 * main() nevers returns; we exit to user mode from a forked process
637 * later on.
638 */
639	jbsr	_C_LABEL(mvme68k_init)	| additional pre-main initialization
640	movw	#PSL_LOWIPL,%sr		| lower SPL
641	clrw	%sp@-			| vector offset/frame type
642	clrl	%sp@-			| PC - filled in by "execve"
643	movw	#PSL_USER,%sp@-		| in user mode
644	clrl	%sp@-			| stack adjust count and padding
645	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
646	lea	_C_LABEL(lwp0),%a0	| save pointer to frame
647	movl	%sp,%a0@(L_MD_REGS)	|   in lwp0.l_md.md_regs
648
649	jra	_C_LABEL(main)		| main()
650
651#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177)
652/*
653 * Probe for a memory controller ASIC (MEMC040 or MEMECC) at the
654 * address in a0. If found, return the size in bytes of any RAM
655 * controlled by the ASIC in d0. Otherwise return zero.
656 */
657ASLOCAL(memc040read)
658	moveml	%d1-%d2/%a1-%a2,%sp@-	| save scratch regs
659	movc	%vbr,%d2		| Save vbr
660	RELOC(vectab,%a2)		| Install our own vectab, temporarily
661	movc	%a2,%vbr
662	ASRELOC(Lmemc040berr,%a1)	| get address of bus error handler
663	movl	%a2@(8),%sp@-		| Save current bus error handler addr
664	movl	%a1,%a2@(8)		| Install our own handler
665	movl	%sp,%d0			| Save current stack pointer value
666	movql	#0x07,%d1
667	andb	%a0@,%d1		| Access MEMC040/MEMECC
668	movl	#0x400000,%d0
669	lsll	%d1,%d0			| Convert to memory size, in bytes
670Lmemc040ret:
671	movc	%d2,%vbr		| Restore original vbr
672	movl	%sp@+,%a2@(8)		| Restore original bus error handler
673	moveml  %sp@+,%d1-%d2/%a1-%a2
674	rts
675/*
676 * If the memory controller doesn't exist, we get a bus error trying
677 * to access a0@ above. Control passes here, where we flag 'no bytes',
678 * ditch the exception frame and return as normal.
679 */
680Lmemc040berr:
681	movl	%d0,%sp			| Get rid of the exception frame
682	movql	#0,%d0			| No ASIC at this location, then!
683	jbra	Lmemc040ret		| Done
684#endif
685
686/*
687 * Trap/interrupt vector routines
688 */
689#include <m68k/m68k/trap_subr.s>
690
691/*
692 * Use common m68k bus error and address error handlers.
693 */
694#include <m68k/m68k/busaddrerr.s>
695
696/*
697 * FP exceptions.
698 */
699ENTRY_NOPROFILE(fpfline)
700#if defined(M68040)
701	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
702	jne	Lfp_unimp		| no, skip FPSP
703	cmpw	#0x202c,%sp@(6)		| format type 2?
704	jne	_C_LABEL(illinst)	| no, not an FP emulation
705#ifdef FPSP
706	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
707#else
708	clrl	%sp@-			| stack adjust count
709	moveml	#0xFFFF,%sp@-		| save registers
710	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
711	jra	_ASM_LABEL(fault)	| do it
712#endif
713Lfp_unimp:
714#endif /* M68040 */
715	jra	_C_LABEL(illinst)
716
717ENTRY_NOPROFILE(fpunsupp)
718#if defined(M68040)
719	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
720	jne	Lfp_unsupp		| No, skip FPSP
721#ifdef FPSP
722	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
723#else
724	clrl	%sp@-			| stack adjust count
725	moveml	#0xFFFF,%sp@-		| save registers
726	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
727	jra	_ASM_LABEL(fault)	| do it
728#endif
729Lfp_unsupp:
730#endif /* M68040 */
731	jra	_C_LABEL(illinst)
732
733/*
734 * Handles all other FP coprocessor exceptions.
735 * Note that since some FP exceptions generate mid-instruction frames
736 * and may cause signal delivery, we need to test for stack adjustment
737 * after the trap call.
738 */
739ENTRY_NOPROFILE(fpfault)
740	clrl	%sp@-		| stack adjust count
741	moveml	#0xFFFF,%sp@-	| save user registers
742	movl	%usp,%a0	| and save
743	movl	%a0,%sp@(FR_SP)	|   the user stack pointer
744	clrl	%sp@-		| no VA arg
745	movl	_C_LABEL(curpcb),%a0 | current pcb
746	lea	%a0@(PCB_FPCTX),%a0 | address of FP savearea
747	fsave	%a0@		| save state
748#if defined(M68040) || defined(M68060)
749	/* always null state frame on 68040, 68060 */
750	cmpl	#FPU_68040,_C_LABEL(fputype)
751	jge	Lfptnull
752#endif
753	tstb	%a0@		| null state frame?
754	jeq	Lfptnull	| yes, safe
755	clrw	%d0		| no, need to tweak BIU
756	movb	%a0@(1),%d0	| get frame size
757	bset	#3,%a0@(0,%d0:w) | set exc_pend bit of BIU
758Lfptnull:
759	fmovem	%fpsr,%sp@-	| push fpsr as code argument
760	frestore %a0@		| restore state
761	movl	#T_FPERR,%sp@-	| push type arg
762	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
763
764
765/*
766 * Other exceptions only cause four and six word stack frame and require
767 * no post-trap stack adjustment.
768 */
769
770ENTRY_NOPROFILE(badtrap)
771	moveml	#0xC0C0,%sp@-		| save scratch regs
772	movw	%sp@(22),%sp@-		| push exception vector info
773	clrw	%sp@-
774	movl	%sp@(22),%sp@-		| and PC
775	jbsr	_C_LABEL(straytrap)	| report
776	addql	#8,%sp			| pop args
777	moveml	%sp@+,#0x0303		| restore regs
778	jra	_ASM_LABEL(rei)		| all done
779
780ENTRY_NOPROFILE(trap0)
781	clrl	%sp@-			| stack adjust count
782	moveml	#0xFFFF,%sp@-		| save user registers
783	movl	%usp,%a0		| save the user SP
784	movl	%a0,%sp@(FR_SP)		|   in the savearea
785	movl	%d0,%sp@-		| push syscall number
786	jbsr	_C_LABEL(syscall)	| handle it
787	addql	#4,%sp			| pop syscall arg
788	tstl	_C_LABEL(astpending)	| AST pending?
789	jne	Lrei1			| Yup, go deal with it.
790	movl	%sp@(FR_SP),%a0		| grab and restore
791	movl	%a0,%usp		|   user SP
792	moveml	%sp@+,#0x7FFF		| restore most registers
793	addql	#8,%sp			| pop SP and stack adjust
794	rte
795
796/*
797 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
798 *	cachectl(command, addr, length)
799 * command in d0, addr in a1, length in d1
800 */
801ENTRY_NOPROFILE(trap12)
802	movl	_C_LABEL(curlwp),%a0
803	movl	%a0@(L_PROC),%sp@-	| push current proc pointer
804	movl	%d1,%sp@-		| push length
805	movl	%a1,%sp@-		| push addr
806	movl	%d0,%sp@-		| push command
807	jbsr	_C_LABEL(cachectl1)	| do it
808	lea	%sp@(16),%sp		| pop args
809	jra	_ASM_LABEL(rei)		| all done
810
811/*
812 * Trace (single-step) trap.  Kernel-mode is special.
813 * User mode traps are simply passed on to trap().
814 */
815ENTRY_NOPROFILE(trace)
816	clrl	%sp@-			| stack adjust count
817	moveml	#0xFFFF,%sp@-
818	moveq	#T_TRACE,%d0
819
820	| Check PSW and see what happen.
821	|   T=0 S=0	(should not happen)
822	|   T=1 S=0	trace trap from user mode
823	|   T=0 S=1	trace trap on a trap instruction
824	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
825
826	movw	%sp@(FR_HW),%d1		| get PSW
827	notw	%d1			| XXX no support for T0 on 680[234]0
828	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
829	jeq	Lkbrkpt			| yes, kernel breakpoint
830	jra	_ASM_LABEL(fault)	| no, user-mode fault
831
832/*
833 * Trap 15 is used for:
834 *	- GDB breakpoints (in user programs)
835 *	- KGDB breakpoints (in the kernel)
836 *	- trace traps for SUN binaries (not fully supported yet)
837 * User mode traps are simply passed to trap().
838 */
839ENTRY_NOPROFILE(trap15)
840	clrl	%sp@-			| stack adjust count
841	moveml	#0xFFFF,%sp@-
842	moveq	#T_TRAP15,%d0
843	movw	%sp@(FR_HW),%d1		| get PSW
844	andw	#PSL_S,%d1		| from system mode?
845	jne	Lkbrkpt			| yes, kernel breakpoint
846	jra	_ASM_LABEL(fault)	| no, user-mode fault
847
848Lkbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type)
849	| Save the system sp rather than the user sp.
850	movw	#PSL_HIGHIPL,%sr	| lock out interrupts
851	lea	%sp@(FR_SIZE),%a6	| Save stack pointer
852	movl	%a6,%sp@(FR_SP)		|  from before trap
853
854	| If were are not on tmpstk switch to it.
855	| (so debugger can change the stack pointer)
856	movl	%a6,%d1
857	cmpl	#_ASM_LABEL(tmpstk),%d1
858	jls	Lbrkpt2			| already on tmpstk
859	| Copy frame to the temporary stack
860	movl	%sp,%a0			| a0=src
861	lea	_ASM_LABEL(tmpstk)-96,%a1 | a1=dst
862	movl	%a1,%sp			| sp=new frame
863	movql	#FR_SIZE,%d1
864Lbrkpt1:
865	movl	%a0@+,%a1@+
866	subql	#4,%d1
867	jbgt	Lbrkpt1
868
869Lbrkpt2:
870	| Call the trap handler for the kernel debugger.
871	| Do not call trap() to do it, so that we can
872	| set breakpoints in trap() if we want.  We know
873	| the trap type is either T_TRACE or T_BREAKPOINT.
874	| If we have both DDB and KGDB, let KGDB see it first,
875	| because KGDB will just return 0 if not connected.
876	| Save args in d2, a2
877	movl	%d0,%d2			| trap type
878	movl	%sp,%a2			| frame ptr
879#ifdef KGDB
880	| Let KGDB handle it (if connected)
881	movl	%a2,%sp@-		| push frame ptr
882	movl	%d2,%sp@-		| push trap type
883	jbsr	_C_LABEL(kgdb_trap)	| handle the trap
884	addql	#8,%sp			| pop args
885	cmpl	#0,%d0			| did kgdb handle it?
886	jne	Lbrkpt3			| yes, done
887#endif
888#ifdef DDB
889	| Let DDB handle it
890	movl	%a2,%sp@-		| push frame ptr
891	movl	%d2,%sp@-		| push trap type
892	jbsr	_C_LABEL(kdb_trap)	| handle the trap
893	addql	#8,%sp			| pop args
894#endif
895	/* Sun 3 drops into PROM here. */
896Lbrkpt3:
897	| The stack pointer may have been modified, or
898	| data below it modified (by kgdb push call),
899	| so push the hardware frame at the current sp
900	| before restoring registers and returning.
901
902	movl	%sp@(FR_SP),%a0		| modified sp
903	lea	%sp@(FR_SIZE),%a1	| end of our frame
904	movl	%a1@-,%a0@-		| copy 2 longs with
905	movl	%a1@-,%a0@-		| ... predecrement
906	movl	%a0,%sp@(FR_SP)		| sp = h/w frame
907	moveml	%sp@+,#0x7FFF		| restore all but sp
908	movl	%sp@,%sp		| ... and sp
909	rte				| all done
910
911/*
912 * Emulation of VAX REI instruction.
913 *
914 * This code deals with checking for and servicing ASTs
915 * (profiling, scheduling).
916 * After identifying that we need an AST we drop the IPL to allow device
917 * interrupts.
918 *
919 * This code is complicated by the fact that sendsig may have been called
920 * necessitating a stack cleanup.
921 */
922ASENTRY_NOPROFILE(rei)
923	tstl	_C_LABEL(astpending)	| AST pending?
924	jeq	Ldorte			| Nope. Just return.
925	btst	#5,%sp@			| Returning to kernel mode?
926	jne	Ldorte			| Yup. Can't do ASTs
927	movw	#PSL_LOWIPL,%sr		| lower SPL
928	clrl	%sp@-			| stack adjust
929	moveml	#0xFFFF,%sp@-		| save all registers
930	movl	%usp,%a1		| including
931	movl	%a1,%sp@(FR_SP)		|    the users SP
932Lrei1:	clrl	%sp@-			| VA == none
933	clrl	%sp@-			| code == none
934	movl	#T_ASTFLT,%sp@-		| type == async system trap
935	pea	%sp@(12)		| fp == address of trap frame
936	jbsr	_C_LABEL(trap)		| go handle it
937	lea	%sp@(16),%sp		| pop value args
938	movl	%sp@(FR_SP),%a0		| restore user SP
939	movl	%a0,%usp		|   from save area
940	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
941	jne	Laststkadj		| yes, go to it
942	moveml	%sp@+,#0x7FFF		| no, restore most user regs
943	addql	#8,%sp			| toss SP and stack adjust
944Ldorte:	rte				| and do real RTE
945
946Laststkadj:
947	lea	%sp@(FR_HW),%a1		| pointer to HW frame
948	addql	#8,%a1			| source pointer
949	movl	%a1,%a0			| source
950	addw	%d0,%a0			|  + hole size = dest pointer
951	movl	%a1@-,%a0@-		| copy
952	movl	%a1@-,%a0@-		|  8 bytes
953	movl	%a0,%sp@(FR_SP)		| new SSP
954	moveml	%sp@+,#0x7FFF		| restore user registers
955	movl	%sp@,%sp		| and our SP
956	rte				| and do real RTE
957
958/*
959 * Primitives
960 */
961
962/*
963 * Use common m68k process/lwp switch and context save subroutines.
964 */
965#define	FPCOPROC	/* XXX: Temp. Reqd. */
966#include <m68k/m68k/switch_subr.s>
967
968
969#if defined(M68040) || defined(M68060)
970ENTRY(suline)
971	movl	%sp@(4),%a0		| address to write
972	movl	_C_LABEL(curpcb),%a1	| current pcb
973	movl	#Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault
974	movl	%sp@(8),%a1		| address of line
975	movl	%a1@+,%d0		| get lword
976	movsl	%d0,%a0@+		| put lword
977	nop				| sync
978	movl	%a1@+,%d0		| get lword
979	movsl	%d0,%a0@+		| put lword
980	nop				| sync
981	movl	%a1@+,%d0		| get lword
982	movsl	%d0,%a0@+		| put lword
983	nop				| sync
984	movl	%a1@+,%d0		| get lword
985	movsl	%d0,%a0@+		| put lword
986	nop				| sync
987	moveq	#0,%d0			| indicate no fault
988	jra	Lsldone
989Lslerr:
990	moveq	#-1,%d0
991Lsldone:
992	movl	_C_LABEL(curpcb),%a1	| current pcb
993	clrl	%a1@(PCB_ONFAULT)	| clear fault address
994	rts
995#endif
996
997
998ENTRY(ecacheon)
999	rts
1000
1001ENTRY(ecacheoff)
1002	rts
1003
1004/*
1005 * _delay(unsigned N)
1006 *
1007 * Delay for at least (N/1024) microseconds.
1008 * This routine depends on the variable:  delay_divisor
1009 * which should be set based on the CPU clock rate.
1010 */
1011ENTRY_NOPROFILE(_delay)
1012	| d0 = arg = (usecs << 10)
1013	movl	%sp@(4),%d0
1014	| d1 = delay_divisor
1015	movl	_C_LABEL(delay_divisor),%d1
1016	jra	L_delay			/* Jump into the loop! */
1017
1018	/*
1019	 * Align the branch target of the loop to a half-line (8-byte)
1020	 * boundary to minimize cache effects.  This guarantees both
1021	 * that there will be no prefetch stalls due to cache line burst
1022	 * operations and that the loop will run from a single cache
1023	 * half-line.
1024	 */
1025#ifdef __ELF__
1026	.align	8
1027#else
1028	.align	3
1029#endif
1030L_delay:
1031	subl	%d1,%d0
1032	jgt	L_delay
1033	rts
1034
1035/*
1036 * Handle the nitty-gritty of rebooting the machine.
1037 * Basically we just turn off the MMU, restore the Bug's initial VBR
1038 * and either return to Bug or jump through the ROM reset vector
1039 * depending on how the system was halted.
1040 */
1041ENTRY_NOPROFILE(doboot)
1042	movw	#PSL_HIGHIPL,%sr
1043	movl	_C_LABEL(boothowto),%d1	| load howto
1044	movl	%sp@(4),%d2		| arg
1045	movl	_C_LABEL(saved_vbr),%d3	| Fetch Bug's original VBR value
1046	movl	_C_LABEL(machineid),%d4	| What type of board is this?
1047	movl	#CACHE_OFF,%d0
1048#if defined(M68040) || defined(M68060)
1049	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040/68060?
1050	jne	Lnocache0		| no, skip
1051	.word	0xf4f8			| cpusha bc - push and invalidate caches
1052	nop
1053	movl	#CACHE40_OFF,%d0
1054#endif
1055Lnocache0:
1056	movc	%d0,%cacr		| disable on-chip cache(s)
1057
1058#if defined(M68040) || defined(M68060)
1059	cmpl	#MMU_68040,_C_LABEL(mmutype)
1060	jne	LmotommuF
1061	movql	#0,%d0
1062	movc	%d0,%cacr
1063	.long	0x4e7b0003              | movc d0,tc
1064	jra	Lbootcommon
1065LmotommuF:
1066#endif
1067	clrl	%sp@-			| value for pmove to TC (turn off MMU)
1068	pmove	%sp@,%tc		| disable MMU
1069	addql	#4,%sp
1070
1071Lbootcommon:
1072	/*
1073	 * MMU Switched off by now, so relocate all absolute references
1074	 */
1075	ASRELOC(tmpstk, %sp)		| physical SP in case of NMI
1076	movc	%d3,%vbr		| Restore Bug's VBR
1077	andl	#RB_SBOOT, %d1		| mask off
1078	jbne	Lsboot			| sboot?
1079	/* NOT sboot */
1080	tstl	%d2			| autoboot?
1081	jbeq	Ldoreset		| yes!
1082	CALLBUG(MVMEPROM_EXIT)		| return to bug
1083	/* NOTREACHED */
1084
1085Ldoreset:
1086	movl	#0xff800000,%a0		| Bug's reset vector address
1087	movl	%a0@+, %a7		| get SP
1088	movl	%a0@, %a0		| get PC
1089	jmp	%a0@			| go!
1090
1091Lsboot: /* sboot */
1092	tstl	%d2			| autoboot?
1093	jbeq	1f			| yes!
1094	jmp 	0x4000			| back to sboot
10951:	jmp	0x400a			| tell sboot to reboot us
1096
1097
1098/*
1099 * Misc. global variables.
1100 */
1101	.data
1102
1103GLOBAL(machineid)
1104	.long	MVME_147	| default to MVME_147
1105
1106GLOBAL(mmutype)
1107	.long	MMU_68030	| default to MMU_68030
1108
1109GLOBAL(cputype)
1110	.long	CPU_68030	| default to CPU_68030
1111
1112GLOBAL(fputype)
1113	.long	FPU_68882	| default to FPU_68882
1114
1115/*
1116 * Information from first stage boot program
1117 */
1118GLOBAL(bootpart)
1119	.long	0
1120GLOBAL(bootdevlun)
1121	.long	0
1122GLOBAL(bootctrllun)
1123	.long	0
1124GLOBAL(bootaddr)
1125	.long	0
1126
1127GLOBAL(intiobase)
1128	.long	0		| KVA of base of internal IO space
1129
1130GLOBAL(intiolimit)
1131	.long	0		| KVA of end of internal IO space
1132
1133GLOBAL(intiobase_phys)
1134	.long	0		| PA of board's I/O registers
1135
1136GLOBAL(intiotop_phys)
1137	.long	0		| PA of top of board's I/O registers
1138