xref: /netbsd/sys/arch/hp300/hp300/locore.s (revision 94439884)
1/*	$NetBSD: locore.s,v 1.173 2022/05/30 09:56:03 andvar 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/*
41 * Copyright (c) 1994, 1995 Gordon W. Ross
42 * Copyright (c) 1988 University of Utah.
43 *
44 * This code is derived from software contributed to Berkeley by
45 * the Systems Programming Group of the University of Utah Computer
46 * Science Department.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 *    notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 *    notice, this list of conditions and the following disclaimer in the
55 *    documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 *    must display the following acknowledgement:
58 *	This product includes software developed by the University of
59 *	California, Berkeley and its contributors.
60 * 4. Neither the name of the University nor the names of its contributors
61 *    may be used to endorse or promote products derived from this software
62 *    without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * from: Utah $Hdr: locore.s 1.66 92/12/22$
77 *
78 *	@(#)locore.s	8.6 (Berkeley) 5/27/94
79 */
80
81#include "opt_compat_netbsd.h"
82#include "opt_compat_sunos.h"
83#include "opt_ddb.h"
84#include "opt_fpsp.h"
85#include "opt_kgdb.h"
86#include "opt_lockdebug.h"
87#include "opt_fpu_emulate.h"
88#include "opt_m68k_arch.h"
89
90#include "assym.h"
91#include <machine/asm.h>
92#include <machine/trap.h>
93
94#include "opt_useleds.h"
95#ifdef USELEDS
96#include <hp300/hp300/leds.h>
97#endif
98
99#include "audio.h"
100#include "ksyms.h"
101
102#define MMUADDR(ar)	movl	_C_LABEL(MMUbase),ar
103#define CLKADDR(ar)	movl	_C_LABEL(CLKbase),ar
104
105/*
106 * This is for kvm_mkdb, and should be the address of the beginning
107 * of the kernel text segment (not necessarily the same as kernbase).
108 */
109	.text
110GLOBAL(kernel_text)
111
112/*
113 * Clear and skip the first page of text; it will not be mapped at
114 * VA 0.
115 *
116 * The bootloader places the bootinfo in this page, and we allocate
117 * a VA for it and map it later.
118 */
119	.fill	PAGE_SIZE/4,4,0
120
121/*
122 * Temporary stack for a variety of purposes.
123 * Try and make this the first thing is the data segment so it
124 * is page aligned.  Note that if we overflow here, we run into
125 * our text segment.
126 */
127	.data
128	.space	PAGE_SIZE
129ASLOCAL(tmpstk)
130
131#include <hp300/hp300/vectors.s>
132
133/*
134 * Macro to relocate a symbol, used before MMU is enabled.
135 */
136#ifdef __STDC__
137#define	IMMEDIATE		#
138#define	_RELOC(var, ar)			\
139	movel	IMMEDIATE var,ar;	\
140	addl	%a5,ar
141#else
142#define	_RELOC(var, ar)			\
143	movel	#var,ar;		\
144	addl	%a5,ar
145#endif /* __STDC__ */
146
147#define	RELOC(var, ar)		_RELOC(_C_LABEL(var), ar)
148#define	ASRELOC(var, ar)	_RELOC(_ASM_LABEL(var), ar)
149
150/*
151 * Final bits of grunt work required to reboot the system.  The MMU
152 * must be disabled when this is invoked.
153 */
154#define DOREBOOT						\
155	/* Reset Vector Base Register to what PROM expects. */  \
156	movl	#0,%d0;						\
157	movc	%d0,%vbr;					\
158	/* Jump to REQ_REBOOT */				\
159	jmp	0x1A4;
160
161/*
162 * Initialization
163 *
164 * A4 contains the address of the end of the symtab
165 * A5 contains physical load point from boot
166 * VBR contains zero from ROM.  Exceptions will continue to vector
167 * through ROM until MMU is turned on at which time they will vector
168 * through our table (vectors.s).
169 */
170
171BSS(lowram,4)
172BSS(esym,4)
173
174ASENTRY_NOPROFILE(start)
175	movw	#PSL_HIGHIPL,%sr	| no interrupts
176	ASRELOC(tmpstk, %a0)
177	movl	%a0,%sp			| give ourselves a temporary stack
178	RELOC(esym, %a0)
179#if 1
180	movl	%a4,%a0@		| store end of symbol table
181#else
182	clrl	%a0@			| no symbol table, yet
183#endif
184	RELOC(lowram, %a0)
185	movl	%a5,%a0@		| store start of physical memory
186	movl	#CACHE_OFF,%d0
187	movc	%d0,%cacr		| clear and disable on-chip cache(s)
188
189/* check for internal HP-IB in SYSFLAG */
190	btst	#5,0xfffffed2		| internal HP-IB?
191	jeq	Lhaveihpib		| yes, have HP-IB just continue
192	RELOC(internalhpib, %a0)
193	movl	#0,%a0@			| no, clear associated address
194Lhaveihpib:
195
196	RELOC(boothowto, %a0)		| save reboot flags
197	movl	%d7,%a0@
198	RELOC(bootdev, %a0)		|   and boot device
199	movl	%d6,%a0@
200
201	/*
202	 * All data registers are now free.  All address registers
203	 * except %a5 are free.  %a5 is used by the RELOC() macro,
204	 * and cannot be used until after the MMU is enabled.
205	 */
206
207/* determine our CPU/MMU combo - check for all regardless of kernel config */
208	movl	#INTIOBASE+MMUBASE,%a1
209	movl	#DC_FREEZE,%d0		| data freeze bit
210	movc	%d0,%cacr		|   only exists on 68030
211	movc	%cacr,%d0		| read it back
212	tstl	%d0			| zero?
213	jeq	Lnot68030		| yes, we have 68020/68040
214
215	/*
216	 * 68030 models
217	 */
218
219	RELOC(mmutype, %a0)		| no, we have 68030
220	movl	#MMU_68030,%a0@		| set to reflect 68030 PMMU
221	RELOC(cputype, %a0)
222	movl	#CPU_68030,%a0@		| and 68030 CPU
223	RELOC(machineid, %a0)
224	movl	#0x80,%a1@(MMUCMD)	| set magic cookie
225	movl	%a1@(MMUCMD),%d0	| read it back
226	btst	#7,%d0			| cookie still on?
227	jeq	Lnot370			| no, 360, 362 or 375
228	movl	#0,%a1@(MMUCMD)		| clear magic cookie
229	movl	%a1@(MMUCMD),%d0	| read it back
230	btst	#7,%d0			| still on?
231	jeq	Lisa370			| no, must be a 370
232	movl	#HP_340,%a0@		| yes, must be a 340
233	jra	Lstart1
234Lnot370:
235	movl	#HP_360,%a0@		| type is at least a 360
236	movl	#0,%a1@(MMUCMD)		| clear magic cookie2
237	movl	%a1@(MMUCMD),%d0	| read it back
238	btst	#16,%d0			| still on?
239	jeq	Lisa36x			| no, must be a 360 or a 362
240	RELOC(mmuid, %a0)		| save MMU ID
241	lsrl	#MMUID_SHIFT,%d0
242	andl	#MMUID_MASK,%d0
243	movl	%d0,%a0@
244	RELOC(machineid, %a0)
245	cmpb	#MMUID_345,%d0		| are we a 345?
246	beq	Lisa345
247	cmpb	#MMUID_375,%d0		| how about a 375?
248	beq	Lisa375
249	movl	#HP_400,%a0@		| must be a 400
250	jra	Lhaspac
251Lisa36x:
252	/*
253	 * If we found a 360, we need to check for a 362 (neither the 360
254	 * nor the 362 have a nonzero mmuid). Identify 362 by checking
255	 * on-board VRX framebuffer which has secid 0x11 at dio scode 132.
256	 */
257	movl	#DIOII_BASE,%a0		| probe dio scode 132
258	ASRELOC(phys_badaddr,%a3)
259	jbsr	%a3@
260	tstl	%d0			| device at scode 132?
261	jne	Lstart1			| no, not 362, assume 360
262	movb	%a0@(DIO_IDOFF),%d0
263	cmpb	#DIO_DEVICE_ID_FRAMEBUFFER,%d0	| framebuffer?
264	jne	Lstart1			| no, not 362, assume 360
265	movb	%a0@(DIO_SECIDOFF),%d0
266	cmpb	#0x11,%d0		| VRX sti on 362?
267	jne	Lstart1			| no, not 362, assume 360
268	RELOC(machineid,%a0)
269	movl	#HP_362,%a0@
270	jra	Lstart1
271Lisa345:
272	movl	#HP_345,%a0@
273	jra	Lhaspac
274Lisa375:
275	movl	#HP_375,%a0@
276	jra	Lhaspac
277Lisa370:
278	movl	#HP_370,%a0@		| set to 370
279Lhaspac:
280	RELOC(ectype, %a0)
281	movl	#EC_PHYS,%a0@		| also has a physical address cache
282	jra	Lstart1
283
284	/*
285	 * End of 68030 section
286	 */
287
288Lnot68030:
289	bset	#31,%d0			| data cache enable bit
290	movc	%d0,%cacr		|   only exists on 68040
291	movc	%cacr,%d0		| read it back
292	tstl	%d0			| zero?
293	beq	Lis68020		| yes, we have 68020
294	moveq	#0,%d0			| now turn it back off
295	movec	%d0,%cacr		|   before we access any data
296
297	/*
298	 * 68040 models
299	 */
300
301	RELOC(mmutype, %a0)
302	movl	#MMU_68040,%a0@		| with a 68040 MMU
303	RELOC(cputype, %a0)
304	movl	#CPU_68040,%a0@		| and a 68040 CPU
305	RELOC(fputype, %a0)
306	movl	#FPU_68040,%a0@		| ...and FPU
307	RELOC(ectype, %a0)
308	movl	#EC_NONE,%a0@		| and no cache (for now XXX)
309	RELOC(mmuid,%a0)		| save MMU ID
310	movl	%a1@(MMUCMD),%d0
311	lsrl	#MMUID_SHIFT,%d0
312	andl	#MMUID_MASK,%d0
313	movl	%d0,%a0@
314	RELOC(machineid, %a0)
315	cmpb	#MMUID_425_T,%d0	| are we a 425t?
316	jeq	Lisa425
317	cmpb	#MMUID_425_S,%d0	| how about 425s?
318	jeq	Lisa425
319	cmpb	#MMUID_425_E,%d0	| or maybe a 425e?
320	jeq	Lisa425
321	cmpb	#MMUID_433_T,%d0	| or a 433t?
322	jeq	Lisa433
323	cmpb	#MMUID_433_S,%d0	| or a 433s?
324	jeq	Lisa433
325	cmpb	#MMUID_385,%d0		| or a 385?
326	jeq	Lisa385
327	cmpb	#MMUID_382,%d0		| or a 382?
328	jeq	Lisa382
329	movl	#HP_380,%a0@		| guess we're a 380
330	jra	Lstart1
331Lisa425:
332	movl	#HP_425,%a0@
333	jra	Lstart1
334Lisa433:
335	movl	#HP_433,%a0@
336	jra	Lstart1
337Lisa385:
338	movl	#HP_385,%a0@
339	jra	Lstart1
340Lisa382:
341	movl	#HP_382,%a0@
342	jra	Lstart1
343
344	/*
345	 * End of 68040 section
346	 */
347
348	/*
349	 * 68020 models
350	 */
351
352Lis68020:
353	RELOC(fputype, %a0)		| all of the 68020 systems
354	movl	#FPU_68881,%a0@		|   have a 68881 FPU
355	movl	#1,%a1@(MMUCMD)		| a 68020, write HP MMU location
356	movl	%a1@(MMUCMD),%d0	| read it back
357	btst	#0,%d0			| non-zero?
358	jne	Lishpmmu		| yes, we have HP MMU
359	RELOC(mmutype, %a0)
360	movl	#MMU_68851,%a0@		| no, we have PMMU
361	RELOC(machineid, %a0)
362	movl	#HP_330,%a0@		| and 330 CPU
363	jra	Lstart1
364Lishpmmu:
365	RELOC(ectype, %a0)		| 320 or 350
366	movl	#EC_VIRT,%a0@		| both have a virtual address cache
367	movl	#0x80,%a1@(MMUCMD)	| set magic cookie
368	movl	%a1@(MMUCMD),%d0	| read it back
369	btst	#7,%d0			| cookie still on?
370	jeq	Lis320			| no, just a 320
371	RELOC(machineid, %a0)
372	movl	#HP_350,%a0@		| yes, a 350
373	jra	Lstart1
374Lis320:
375	RELOC(machineid, %a0)
376	movl	#HP_320,%a0@
377
378	/*
379	 * End of 68020 section
380	 */
381
382Lstart1:
383	/*
384	 * Now that we know what CPU we have, initialize the address error
385	 * and bus error handlers in the vector table:
386	 *
387	 *	vectab+8	bus error
388	 *	vectab+12	address error
389	 */
390	RELOC(cputype, %a0)
391#if 0
392	/* XXX assembler/linker feature/bug */
393	RELOC(vectab, %a2)
394#else
395	movl	#_C_LABEL(vectab),%a2
396	addl	%a5,%a2
397#endif
398#if defined(M68040)
399	cmpl	#CPU_68040,%a0@		| 68040?
400	jne	1f			| no, skip
401	movl	#_C_LABEL(buserr40),%a2@(8)
402	movl	#_C_LABEL(addrerr4060),%a2@(12)
403	jra	Lstart2
4041:
405#endif
406#if defined(M68020) || defined(M68030)
407	cmpl	#CPU_68040,%a0@		| 68040?
408	jeq	1f			| yes, skip
409	movl	#_C_LABEL(busaddrerr2030),%a2@(8)
410	movl	#_C_LABEL(busaddrerr2030),%a2@(12)
411	jra	Lstart2
4121:
413#endif
414	/* Config botch; no hope. */
415	DOREBOOT
416
417Lstart2:
418	movl	#0,%a1@(MMUCMD)		| clear out MMU again
419/* initialize source/destination control registers for movs */
420	moveq	#FC_USERD,%d0		| user space
421	movc	%d0,%sfc		|   as source
422	movc	%d0,%dfc		|   and destination of transfers
423/* save the first PA as bootinfo_pa to map it to a virtual address later. */
424	movl	%a5,%d0			| lowram value from ROM via boot
425	RELOC(bootinfo_pa, %a0)
426	movl	%d0,%a0@		| save the lowram as bootinfo PA
427/* initialize memory sizes (for pmap_bootstrap) */
428	movl	#MAXADDR,%d1		| last page
429	moveq	#PGSHIFT,%d2
430	lsrl	%d2,%d1			| convert to page (click) number
431	RELOC(maxmem, %a0)
432	movl	%d1,%a0@		| save as maxmem
433	lsrl	%d2,%d0			| convert the lowram to page number
434	subl	%d0,%d1			| compute amount of RAM present
435	RELOC(physmem, %a0)
436	movl	%d1,%a0@		| and physmem
437
438/* configure kernel and lwp0 VA space so we can get going */
439#if NKSYMS || defined(DDB) || defined(MODULAR)
440	RELOC(esym,%a0)			| end of static kernel test/data/syms
441	movl	%a0@,%d5
442	jne	Lstart3
443#endif
444	movl	#_C_LABEL(end),%d5	| end of static kernel text/data
445Lstart3:
446	addl	#PAGE_SIZE-1,%d5
447	andl	#PG_FRAME,%d5		| round to a page
448	movl	%d5,%a4
449	addl	%a5,%a4			| convert to PA
450	pea	%a5@			| firstpa
451	pea	%a4@			| nextpa
452	RELOC(pmap_bootstrap,%a0)
453	jbsr	%a0@			| pmap_bootstrap(firstpa, nextpa)
454	addql	#8,%sp
455
456/*
457 * Prepare to enable MMU.
458 * Since the kernel is not mapped logical == physical we must insure
459 * that when the MMU is turned on, all prefetched addresses (including
460 * the PC) are valid.  In order guarantee that, we use the last physical
461 * page (which is conveniently mapped == VA) and load it up with enough
462 * code to defeat the prefetch, then we execute the jump back to here.
463 *
464 * Is this all really necessary, or am I paranoid??
465 */
466	RELOC(Sysseg_pa, %a0)		| system segment table addr
467	movl	%a0@,%d1		| read value (a PA)
468	RELOC(mmutype, %a0)
469	tstl	%a0@			| HP MMU?
470	jeq	Lhpmmu2			| yes, skip
471	cmpl	#MMU_68040,%a0@		| 68040?
472	jne	Lmotommu1		| no, skip
473	.long	0x4e7b1807		| movc %d1,%srp
474	jra	Lstploaddone
475Lmotommu1:
476	RELOC(protorp, %a0)
477	movl	#0x80000202,%a0@	| nolimit + share global + 4 byte PTEs
478	movl	%d1,%a0@(4)		| + segtable address
479	pmove	%a0@,%srp		| load the supervisor root pointer
480	movl	#0x80000002,%a0@	| reinit upper half for CRP loads
481	jra	Lstploaddone		| done
482Lhpmmu2:
483	moveq	#PGSHIFT,%d2
484	lsrl	%d2,%d1			| convert to page frame
485	movl	%d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register
486Lstploaddone:
487	lea	MAXADDR,%a2		| PA of last RAM page
488#if 0
489	ASRELOC(Lhighcode, %a1)		| addr of high code
490	ASRELOC(Lehighcode, %a3)	| end addr
491#else
492	/* don't want pc-relative addressing */
493	.word	0x43f9			| lea Lhighcode, %a1
494	.long	Lhighcode
495	addl	%a5, %a1
496	.word	0x47f9			| lea Lehighcode, %a3
497	.long	Lehighcode
498	addl	%a5, %a3
499#endif
500Lcodecopy:
501	movw	%a1@+,%a2@+		| copy a word
502	cmpl	%a3,%a1			| done yet?
503	jcs	Lcodecopy		| no, keep going
504	jmp	MAXADDR			| go for it!
505
506	/*
507	 * BEGIN MMU TRAMPOLINE.  This section of code is not
508	 * executed in-place.  It's copied to the last page
509	 * of RAM (mapped va == pa) and executed there.
510	 */
511
512Lhighcode:
513	/*
514	 * Set up the vector table, and race to get the MMU
515	 * enabled.
516	 */
517	movl	#_C_LABEL(vectab),%d0	| set Vector Base Register
518	movc	%d0,%vbr
519
520	RELOC(mmutype, %a0)
521	tstl	%a0@			| HP MMU?
522	jeq	Lhpmmu3			| yes, skip
523	cmpl	#MMU_68040,%a0@		| 68040?
524	jne	Lmotommu2		| no, skip
525	movw	#0,INTIOBASE+MMUBASE+MMUCMD+2
526	movw	#MMU_IEN+MMU_CEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD+2
527					| enable FPU and caches
528	moveq	#0,%d0			| ensure TT regs are disabled
529	.long	0x4e7b0004		| movc %d0,%itt0
530	.long	0x4e7b0005		| movc %d0,%itt1
531	.long	0x4e7b0006		| movc %d0,%dtt0
532	.long	0x4e7b0007		| movc %d0,%dtt1
533	.word	0xf4d8			| cinva bc
534	.word	0xf518			| pflusha
535#if PGSHIFT == 13
536	movl	#0xc000,%d0
537#else
538	movl	#0x8000,%d0
539#endif
540	.long	0x4e7b0003		| movc %d0,%tc
541	movl	#CACHE40_ON,%d0
542	movc	%d0,%cacr		| turn on both caches
543	jmp	Lenab1:l		| forced not be pc-relative
544Lmotommu2:
545	movl	#MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD
546					| enable 68881 and i-cache
547	pflusha
548	RELOC(prototc, %a2)
549#if PGSHIFT == 13
550	movl	#0x82d08b00,%a2@	| value to load TC with
551#else
552	movl	#0x82c0aa00,%a2@	| value to load TC with
553#endif
554	pmove	%a2@,%tc		| load it
555	jmp	Lenab1:l		| forced not be pc-relative
556Lhpmmu3:
557	movl	#0,INTIOBASE+MMUBASE+MMUCMD		| clear external cache
558	movl	#MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD	| turn on MMU
559	jmp	Lenab1:l		| forced not be pc-relative
560Lehighcode:
561
562	/*
563	 * END MMU TRAMPOLINE.  Address register %a5 is now free.
564	 */
565
566/*
567 * Should be running mapped from this point on
568 */
569Lenab1:
570	lea	_ASM_LABEL(tmpstk),%sp	| temporary stack
571/* call final pmap setup */
572	jbsr	_C_LABEL(pmap_bootstrap_finalize)
573/* set kernel stack, user SP */
574	movl	_C_LABEL(lwp0uarea),%a1	| get lwp0 uarea
575	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
576	movl	#USRSTACK-4,%a2
577	movl	%a2,%usp		| init user SP
578
579	jbsr	_C_LABEL(fpu_probe)
580	movl	%d0,_C_LABEL(fputype)
581	tstl	_C_LABEL(fputype)	| Have an FPU?
582	jeq	Lenab2			| No, skip.
583	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
584	movl	%a1,%sp@-
585	jbsr	_C_LABEL(m68881_restore) | restore it (does not kill %a1)
586	addql	#4,%sp
587Lenab2:
588/* flush TLB and turn on caches */
589	jbsr	_C_LABEL(_TBIA)		| invalidate TLB
590	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
591	jeq	Lnocache0		| yes, cache already on
592	movl	#CACHE_ON,%d0
593	movc	%d0,%cacr		| clear cache(s)
594	tstl	_C_LABEL(ectype)
595	jeq	Lnocache0
596	MMUADDR(%a0)
597	orl	#MMU_CEN,%a0@(MMUCMD)	| turn on external cache
598Lnocache0:
599/* Final setup for call to main(). */
600	jbsr	_C_LABEL(hp300_init)
601
602/*
603 * Create a fake exception frame so that cpu_lwp_fork() can copy it.
604 * main() nevers returns; we exit to user mode from a forked process
605 * later on.
606 */
607	clrw	%sp@-			| vector offset/frame type
608	clrl	%sp@-			| PC - filled in by "execve"
609	movw	#PSL_USER,%sp@-		| in user mode
610	clrl	%sp@-			| stack adjust count and padding
611	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
612	lea	_C_LABEL(lwp0),%a0	| save pointer to frame
613	movl	%sp,%a0@(L_MD_REGS)	|   in lwp0.l_md.md_regs
614
615	jra	_C_LABEL(main)		| main()
616	PANIC("main() returned")
617	/* NOTREACHED */
618
619/*
620 * Trap/interrupt vector routines
621 */
622#include <m68k/m68k/trap_subr.s>
623
624/*
625 * Use common m68k bus error and address error handlers.
626 */
627#include <m68k/m68k/busaddrerr.s>
628
629/*
630 * FP exceptions.
631 */
632ENTRY_NOPROFILE(fpfline)
633#if defined(M68040)
634	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
635	jne	Lfp_unimp		| no, skip FPSP
636	cmpw	#0x202c,%sp@(6)		| format type 2?
637	jne	_C_LABEL(illinst)	| no, not an FP emulation
638Ldofp_unimp:
639#ifdef FPSP
640	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
641#endif
642Lfp_unimp:
643#endif /* M68040 */
644#ifdef FPU_EMULATE
645	clrl	%sp@-			| stack adjust count
646	moveml	#0xFFFF,%sp@-		| save registers
647	moveq	#T_FPEMULI,%d0		| denote as FP emulation trap
648	jra	_ASM_LABEL(fault)	| do it
649#else
650	jra	_C_LABEL(illinst)
651#endif
652
653ENTRY_NOPROFILE(fpunsupp)
654#if defined(M68040)
655	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
656	jne	_C_LABEL(illinst)	| no, treat as illinst
657#ifdef FPSP
658	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
659#endif
660Lfp_unsupp:
661#endif /* M68040 */
662#ifdef FPU_EMULATE
663	clrl	%sp@-			| stack adjust count
664	moveml	#0xFFFF,%sp@-		| save registers
665	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
666	jra	_ASM_LABEL(fault)	| do it
667#else
668	jra	_C_LABEL(illinst)
669#endif
670
671/*
672 * Handles all other FP coprocessor exceptions.
673 * Note that since some FP exceptions generate mid-instruction frames
674 * and may cause signal delivery, we need to test for stack adjustment
675 * after the trap call.
676 */
677ENTRY_NOPROFILE(fpfault)
678	clrl	%sp@-			| stack adjust count
679	moveml	#0xFFFF,%sp@-		| save user registers
680	movl	%usp,%a0		| and save
681	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
682	clrl	%sp@-			| no VA arg
683	movl	_C_LABEL(curpcb),%a0	| current pcb
684	lea	%a0@(PCB_FPCTX),%a0	| address of FP savearea
685	fsave	%a0@			| save state
686#if defined(M68040) || defined(M68060)
687	/* always null state frame on 68040, 68060 */
688	cmpl	#FPU_68040,_C_LABEL(fputype)
689	jge	Lfptnull
690#endif
691	tstb	%a0@			| null state frame?
692	jeq	Lfptnull		| yes, safe
693	clrw	%d0			| no, need to tweak BIU
694	movb	%a0@(1),%d0		| get frame size
695	bset	#3,%a0@(0,%d0:w)	| set exc_pend bit of BIU
696Lfptnull:
697	fmovem	%fpsr,%sp@-		| push %fpsr as code argument
698	frestore %a0@			| restore state
699	movl	#T_FPERR,%sp@-		| push type arg
700	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
701
702/*
703 * Other exceptions only cause four and six word stack frame and require
704 * no post-trap stack adjustment.
705 */
706
707ENTRY_NOPROFILE(badtrap)
708	moveml	#0xC0C0,%sp@-		| save scratch regs
709	movw	%sp@(22),%sp@-		| push exception vector info
710	clrw	%sp@-
711	movl	%sp@(22),%sp@-		| and PC
712	jbsr	_C_LABEL(straytrap)	| report
713	addql	#8,%sp			| pop args
714	moveml	%sp@+,#0x0303		| restore regs
715	jra	_ASM_LABEL(rei)		| all done
716
717ENTRY_NOPROFILE(trap0)
718	clrl	%sp@-			| stack adjust count
719	moveml	#0xFFFF,%sp@-		| save user registers
720	movl	%usp,%a0		| save the user SP
721	movl	%a0,%sp@(FR_SP)		|   in the savearea
722	movl	%d0,%sp@-		| push syscall number
723	jbsr	_C_LABEL(syscall)	| handle it
724	addql	#4,%sp			| pop syscall arg
725	tstl	_C_LABEL(astpending)	| AST pending?
726	jne	Lrei			| yes, handle it via trap
727	movl	%sp@(FR_SP),%a0		| grab and restore
728	movl	%a0,%usp		|   user SP
729	moveml	%sp@+,#0x7FFF		| restore most registers
730	addql	#8,%sp			| pop SP and stack adjust
731	rte
732
733/*
734 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
735 *	cachectl(command, addr, length)
736 * command in %d0, addr in %a1, length in %d1
737 */
738ENTRY_NOPROFILE(trap12)
739	movl	_C_LABEL(curlwp),%a0
740	movl	%a0@(L_PROC),%sp@-	| push current proc pointer
741	movl	%d1,%sp@-		| push length
742	movl	%a1,%sp@-		| push addr
743	movl	%d0,%sp@-		| push command
744	jbsr	_C_LABEL(cachectl1)	| do it
745	lea	%sp@(16),%sp		| pop args
746	jra	_ASM_LABEL(rei)		| all done
747
748/*
749 * Trace (single-step) trap.  Kernel-mode is special.
750 * User mode traps are simply passed on to trap().
751 */
752ENTRY_NOPROFILE(trace)
753	clrl	%sp@-			| stack adjust count
754	moveml	#0xFFFF,%sp@-
755	moveq	#T_TRACE,%d0
756
757	| Check PSW and see what happen.
758	|   T=0 S=0	(should not happen)
759	|   T=1 S=0	trace trap from user mode
760	|   T=0 S=1	trace trap on a trap instruction
761	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
762
763	movw	%sp@(FR_HW),%d1		| get PSW
764	notw	%d1			| XXX no support for T0 on 680[234]0
765	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
766	jeq	Lkbrkpt			| yes, kernel breakpoint
767	jra	_ASM_LABEL(fault)	| no, user-mode fault
768
769/*
770 * Trap 15 is used for:
771 *	- GDB breakpoints (in user programs)
772 *	- KGDB breakpoints (in the kernel)
773 *	- trace traps for SUN binaries (not fully supported yet)
774 * User mode traps are simply passed to trap().
775 */
776ENTRY_NOPROFILE(trap15)
777	clrl	%sp@-			| stack adjust count
778	moveml	#0xFFFF,%sp@-
779	moveq	#T_TRAP15,%d0
780	movw	%sp@(FR_HW),%d1		| get PSW
781	andw	#PSL_S,%d1		| from system mode?
782	jne	Lkbrkpt			| yes, kernel breakpoint
783	jra	_ASM_LABEL(fault)	| no, user-mode fault
784
785Lkbrkpt: | Kernel-mode breakpoint or trace trap. (%d0=trap_type)
786	| Save the system sp rather than the user sp.
787	movw	#PSL_HIGHIPL,%sr	| lock out interrupts
788	lea	%sp@(FR_SIZE),%a6	| Save stack pointer
789	movl	%a6,%sp@(FR_SP)		|  from before trap
790
791	| If were are not on tmpstk switch to it.
792	| (so debugger can change the stack pointer)
793	movl	%a6,%d1
794	cmpl	#_ASM_LABEL(tmpstk),%d1
795	jls	Lbrkpt2			| already on tmpstk
796	| Copy frame to the temporary stack
797	movl	%sp,%a0			| %a0=src
798	lea	_ASM_LABEL(tmpstk)-96,%a1 | %a1=dst
799	movl	%a1,%sp			| %sp=new frame
800	moveq	#FR_SIZE,%d1
801Lbrkpt1:
802	movl	%a0@+,%a1@+
803	subql	#4,%d1
804	jgt	Lbrkpt1
805
806Lbrkpt2:
807	| Call the trap handler for the kernel debugger.
808	| Do not call trap() to do it, so that we can
809	| set breakpoints in trap() if we want.  We know
810	| the trap type is either T_TRACE or T_BREAKPOINT.
811	| If we have both DDB and KGDB, let KGDB see it first,
812	| because KGDB will just return 0 if not connected.
813	| Save args in %d2, %a2
814	movl	%d0,%d2			| trap type
815	movl	%sp,%a2			| frame ptr
816#ifdef KGDB
817	| Let KGDB handle it (if connected)
818	movl	%a2,%sp@-		| push frame ptr
819	movl	%d2,%sp@-		| push trap type
820	jbsr	_C_LABEL(kgdb_trap)	| handle the trap
821	addql	#8,%sp			| pop args
822	cmpl	#0,%d0			| did kgdb handle it?
823	jne	Lbrkpt3			| yes, done
824#endif
825#ifdef DDB
826	| Let DDB handle it
827	movl	%a2,%sp@-		| push frame ptr
828	movl	%d2,%sp@-		| push trap type
829	jbsr	_C_LABEL(kdb_trap)	| handle the trap
830	addql	#8,%sp			| pop args
831#if 0	/* not needed on hp300 */
832	cmpl	#0,%d0			| did ddb handle it?
833	jne	Lbrkpt3			| yes, done
834#endif
835#endif
836	/* Sun 3 drops into PROM here. */
837Lbrkpt3:
838	| The stack pointer may have been modified, or
839	| data below it modified (by kgdb push call),
840	| so push the hardware frame at the current sp
841	| before restoring registers and returning.
842
843	movl	%sp@(FR_SP),%a0		| modified %sp
844	lea	%sp@(FR_SIZE),%a1	| end of our frame
845	movl	%a1@-,%a0@-		| copy 2 longs with
846	movl	%a1@-,%a0@-		| ... predecrement
847	movl	%a0,%sp@(FR_SP)		| %sp = h/w frame
848	moveml	%sp@+,#0x7FFF		| restore all but %sp
849	movl	%sp@,%sp		| ... and %sp
850	rte				| all done
851
852/* Use common m68k sigreturn */
853#include <m68k/m68k/sigreturn.s>
854
855/*
856 * Interrupt handlers.
857 * All device interrupts are auto-vectored.  The CPU provides
858 * the vector 0x18+level.  Note we count spurious interrupts, but
859 * we don't do anything else with them.
860 */
861
862/* 64-bit evcnt counter increments */
863#define EVCNT_COUNTER(ipl)					\
864	_C_LABEL(hp300_intr_list) + (ipl)*SIZEOF_HI + HI_EVCNT
865#define EVCNT_INCREMENT(ipl)					\
866	clrl	%d0;						\
867	addql	#1,EVCNT_COUNTER(ipl)+4;			\
868	movel	EVCNT_COUNTER(ipl),%d1;				\
869	addxl	%d0,%d1;					\
870	movel	%d1,EVCNT_COUNTER(ipl)
871
872ENTRY_NOPROFILE(spurintr)	/* level 0 */
873	INTERRUPT_SAVEREG
874	EVCNT_INCREMENT(0)
875	CPUINFO_INCREMENT(CI_NINTR)
876	INTERRUPT_RESTOREREG
877	jra	_ASM_LABEL(rei)
878
879ENTRY_NOPROFILE(intrhand)	/* levels 1 through 5 */
880	addql	#1,_C_LABEL(idepth)	| entering interrupt
881	INTERRUPT_SAVEREG
882	movw	%sp@(22),%sp@-		| push exception vector info
883	clrw	%sp@-
884	jbsr	_C_LABEL(intr_dispatch)	| call dispatch routine
885	addql	#4,%sp
886	INTERRUPT_RESTOREREG
887	subql	#1,_C_LABEL(idepth)	| exiting from interrupt
888	jra	_ASM_LABEL(rei)		| all done
889
890ENTRY_NOPROFILE(lev6intr)	/* level 6: clock */
891	addql	#1,_C_LABEL(idepth)	| entering interrupt
892	INTERRUPT_SAVEREG
893	CLKADDR(%a0)
894	movb	%a0@(CLKSR),%d0		| read clock status
895Lclkagain:
896	btst	#0,%d0			| clear timer1 int immediately to
897	jeq	Lnotim1			|  minimize chance of losing another
898	movpw	%a0@(CLKMSB1),%d1	|  due to statintr processing delay
899	movl	_C_LABEL(clkint),%d1	| clkcounter += clkint
900	addl	%d1,_C_LABEL(clkcounter)
901Lnotim1:
902	btst	#2,%d0			| timer3 interrupt?
903	jeq	Lnotim3			| no, skip statclock
904	movpw	%a0@(CLKMSB3),%d1	| clear timer3 interrupt
905	lea	%sp@(16),%a1		| a1 = &clockframe
906	movl	%d0,%sp@-		| save status
907	movl	%a1,%sp@-
908	jbsr	_C_LABEL(statintr)	| statintr(&frame)
909	addql	#4,%sp
910	movl	%sp@+,%d0		| restore pre-statintr status
911	CLKADDR(%a0)
912Lnotim3:
913	btst	#0,%d0			| timer1 interrupt?
914	jeq	Lrecheck		| no, skip hardclock
915	EVCNT_INCREMENT(6)
916	lea	%sp@(16),%a1		| a1 = &clockframe
917	movl	%a1,%sp@-
918#ifdef USELEDS
919	tstl	_C_LABEL(ledaddr)	| using LEDs?
920	jeq	Lnoleds0		| no, skip this code
921	movl	_ASM_LABEL(heartbeat),%d0 | get tick count
922	addql	#1,%d0			|  increment
923	movl	_C_LABEL(hz),%d1
924	addl	#50,%d1			| get the timing a little closer
925	tstb	_ASM_LABEL(beatstatus)	| time to slow down?
926	jeq	Lslowthrob		| yes, slow down
927	lsrl	#3,%d1			| no, fast throb
928Lslowthrob:
929	lsrl	#1,%d1			| slow throb
930	cmpl	%d0,%d1			| are we there yet?
931	jne	Lnoleds1		| no, nothing to do
932	addqb	#1,_ASM_LABEL(beatstatus) | incr beat status
933	cmpb	#3,_ASM_LABEL(beatstatus) | time to reset?
934	jle	Ltwinkle		  | no, twinkle the lights
935	movb	#0,_ASM_LABEL(beatstatus) | reset the status indicator
936Ltwinkle:
937	movl	#LED_PULSE,%sp@-
938	movl	#LED_DISK+LED_LANRCV+LED_LANXMT,%sp@-
939	clrl	%sp@-
940	jbsr	_C_LABEL(ledcontrol)	| toggle pulse, turn all others off
941	lea	%sp@(12),%sp
942	movql	#0,%d0
943Lnoleds1:
944	movl	%d0,_ASM_LABEL(heartbeat)
945Lnoleds0:
946#endif /* USELEDS */
947	jbsr	_C_LABEL(hardclock)	| hardclock(&frame)
948	addql	#4,%sp
949Lrecheck:
950	CPUINFO_INCREMENT(CI_NINTR)	| chalk up another interrupt
951	CLKADDR(%a0)
952	movb	%a0@(CLKSR),%d0		| see if anything happened
953	jmi	Lclkagain		|  while we were in hardclock/statintr
954#if NAUDIO >0
955	movw	%sp@(22),%sp@-		| push exception vector info
956	clrw	%sp@-
957	jbsr	_C_LABEL(intr_dispatch)	| call dispatch routine
958	addql	#4,%sp
959#endif
960	INTERRUPT_RESTOREREG
961	subql	#1,_C_LABEL(idepth)	| exiting from interrupt
962	jra	_ASM_LABEL(rei)		| all done
963
964ENTRY_NOPROFILE(lev7intr)	/* level 7: parity errors, reset key */
965	clrl	%sp@-
966	moveml	#0xFFFF,%sp@-		| save registers
967	EVCNT_INCREMENT(7)
968	movl	%usp,%a0		| and save
969	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
970	jbsr	_C_LABEL(nmihand)	| call handler
971	movl	%sp@(FR_SP),%a0		| restore
972	movl	%a0,%usp		|   user SP
973	moveml	%sp@+,#0x7FFF		| and remaining registers
974	addql	#8,%sp			| pop SP and stack adjust
975	jra	_ASM_LABEL(rei)		| all done
976
977/*
978 * Emulation of VAX REI instruction.
979 *
980 * This code deals with checking for and servicing
981 * ASTs (profiling, scheduling).
982 * After identifying that we need an AST we drop the IPL
983 * to allow device interrupts.
984 *
985 * This code is complicated by the fact that sendsig may have been called
986 * necessitating a stack cleanup.
987 */
988
989ASENTRY_NOPROFILE(rei)
990	tstl	_C_LABEL(astpending)	| AST pending?
991	jne	1f			| no, done
992	rte
9931:
994	btst	#5,%sp@			| yes, are we returning to user mode?
995	jeq	2f			| no, done
996	rte
9972:
998	movw	#PSL_LOWIPL,%sr		| lower SPL
999	clrl	%sp@-			| stack adjust
1000	moveml	#0xFFFF,%sp@-		| save all registers
1001	movl	%usp,%a1		| including
1002	movl	%a1,%sp@(FR_SP)		|    the users SP
1003Lrei:
1004	clrl	%sp@-			| VA == none
1005	clrl	%sp@-			| code == none
1006	movl	#T_ASTFLT,%sp@-		| type == async system trap
1007	pea	%sp@(12)		| fp == address of trap frame
1008	jbsr	_C_LABEL(trap)		| go handle it
1009	lea	%sp@(16),%sp		| pop value args
1010	movl	%sp@(FR_SP),%a0		| restore user SP
1011	movl	%a0,%usp		|   from save area
1012	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
1013	jne	Laststkadj		| yes, go to it
1014	moveml	%sp@+,#0x7FFF		| no, restore most user regs
1015	addql	#8,%sp			| toss SP and stack adjust
1016	rte				| and do real RTE
1017Laststkadj:
1018	lea	%sp@(FR_HW),%a1		| pointer to HW frame
1019	addql	#8,%a1			| source pointer
1020	movl	%a1,%a0			| source
1021	addw	%d0,%a0			|  + hole size = dest pointer
1022	movl	%a1@-,%a0@-		| copy
1023	movl	%a1@-,%a0@-		|  8 bytes
1024	movl	%a0,%sp@(FR_SP)		| new SSP
1025	moveml	%sp@+,#0x7FFF		| restore user registers
1026	movl	%sp@,%sp		| and our SP
1027	rte				| and do real RTE
1028
1029/*
1030 * Use common m68k sigcode.
1031 */
1032#include <m68k/m68k/sigcode.s>
1033#ifdef COMPAT_SUNOS
1034#include <m68k/m68k/sunos_sigcode.s>
1035#endif
1036
1037/*
1038 * Primitives
1039 */
1040
1041/*
1042 * Use common m68k support routines.
1043 */
1044#include <m68k/m68k/support.s>
1045
1046/*
1047 * Use common m68k process/lwp switch and context save subroutines.
1048 */
1049#define FPCOPROC	/* XXX: Temp. reqd. */
1050#include <m68k/m68k/switch_subr.s>
1051
1052
1053#if defined(M68040)
1054ENTRY(suline)
1055	movl	%sp@(4),%a0		| address to write
1056	movl	_C_LABEL(curpcb),%a1	| current pcb
1057	movl	#Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault
1058	movl	%sp@(8),%a1		| address of line
1059	movl	%a1@+,%d0		| get lword
1060	movsl	%d0,%a0@+		| put lword
1061	nop				| sync
1062	movl	%a1@+,%d0		| get lword
1063	movsl	%d0,%a0@+		| put lword
1064	nop				| sync
1065	movl	%a1@+,%d0		| get lword
1066	movsl	%d0,%a0@+		| put lword
1067	nop				| sync
1068	movl	%a1@+,%d0		| get lword
1069	movsl	%d0,%a0@+		| put lword
1070	nop				| sync
1071	moveq	#0,%d0			| indicate no fault
1072	jra	Lsldone
1073Lslerr:
1074	moveq	#-1,%d0
1075Lsldone:
1076	movl	_C_LABEL(curpcb),%a1	| current pcb
1077	clrl	%a1@(PCB_ONFAULT)	| clear fault address
1078	rts
1079#endif
1080
1081ENTRY(ecacheon)
1082	tstl	_C_LABEL(ectype)
1083	jeq	Lnocache7
1084	MMUADDR(%a0)
1085	orl	#MMU_CEN,%a0@(MMUCMD)
1086Lnocache7:
1087	rts
1088
1089ENTRY(ecacheoff)
1090	tstl	_C_LABEL(ectype)
1091	jeq	Lnocache8
1092	MMUADDR(%a0)
1093	andl	#~MMU_CEN,%a0@(MMUCMD)
1094Lnocache8:
1095	rts
1096
1097/*
1098 * Load a new user segment table pointer.
1099 */
1100ENTRY(loadustp)
1101#if defined(M68K_MMU_MOTOROLA)
1102	tstl	_C_LABEL(mmutype)	| HP MMU?
1103	jeq	Lhpmmu9			| yes, skip
1104	movl	%sp@(4),%d0		| new USTP
1105	moveq	#PGSHIFT,%d1
1106	lsll	%d1,%d0			| convert to addr
1107#if defined(M68040)
1108	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1109	jne	LmotommuC		| no, skip
1110	.word	0xf518			| yes, pflusha
1111	.long	0x4e7b0806		| movc %d0,%urp
1112	rts
1113LmotommuC:
1114#endif
1115	pflusha				| flush entire TLB
1116	lea	_C_LABEL(protorp),%a0	| CRP prototype
1117	movl	%d0,%a0@(4)		| stash USTP
1118	pmove	%a0@,%crp		| load root pointer
1119	movl	#CACHE_CLR,%d0
1120	movc	%d0,%cacr		| invalidate cache(s)
1121	rts
1122Lhpmmu9:
1123#endif
1124#if defined(M68K_MMU_HP)
1125	movl	#CACHE_CLR,%d0
1126	movc	%d0,%cacr		| invalidate cache(s)
1127	MMUADDR(%a0)
1128	movl	%a0@(MMUTBINVAL),%d1	| invalidate TLB
1129	tstl	_C_LABEL(ectype)	| have external VAC?
1130	jle	1f			| no, skip
1131	andl	#~MMU_CEN,%a0@(MMUCMD)	| toggle cache enable
1132	orl	#MMU_CEN,%a0@(MMUCMD)	| to clear data cache
11331:
1134	movl	%sp@(4),%a0@(MMUUSTP)	| load a new USTP
1135#endif
1136	rts
1137
1138ENTRY(ploadw)
1139#if defined(M68K_MMU_MOTOROLA)
1140	movl	%sp@(4),%a0		| address to load
1141#if defined(M68K_MMU_HP)
1142	tstl	_C_LABEL(mmutype)	| HP MMU?
1143	jeq	Lploadwskp		| yes, skip
1144#endif
1145#if defined(M68040)
1146	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1147	jeq	Lploadwskp		| yes, skip
1148#endif
1149	ploadw	#1,%a0@			| pre-load translation
1150Lploadwskp:
1151#endif
1152	rts
1153
1154/*
1155 * _delay(u_int N)
1156 *
1157 * Delay for at least (N/256) microseconds.
1158 * This routine depends on the variable:  delay_divisor
1159 * which should be set based on the CPU clock rate.
1160 */
1161ENTRY_NOPROFILE(_delay)
1162	| %d0 = arg = (usecs << 8)
1163	movl	%sp@(4),%d0
1164	| %d1 = delay_divisor
1165	movl	_C_LABEL(delay_divisor),%d1
1166	jra	L_delay			/* Jump into the loop! */
1167
1168	/*
1169	 * Align the branch target of the loop to a half-line (8-byte)
1170	 * boundary to minimize cache effects.  This guarantees both
1171	 * that there will be no prefetch stalls due to cache line burst
1172	 * operations and that the loop will run from a single cache
1173	 * half-line.
1174	 */
1175	.align	8
1176L_delay:
1177	subl	%d1,%d0
1178	jgt	L_delay
1179	rts
1180
1181/*
1182 * Probe a memory address, and see if it causes a bus error.
1183 * This function is only to be used in physical mode, and before our
1184 * trap vectors are initialized.
1185 * Invoke with address to probe in %a0.
1186 * Alters: %a3 %d0
1187 */
1188#define BUSERR  0xfffffffc
1189ASLOCAL(phys_badaddr)
1190	ASRELOC(_bsave,%a3)
1191	movl	BUSERR,%a3@		| save ROM bus errror handler
1192	ASRELOC(_ssave,%a3)
1193	movl	%sp,%a3@		| and current stack pointer
1194	ASRELOC(catchbad,%a3)
1195	movl	%a3,BUSERR		| plug in our handler
1196	movb	%a0@,%d0		| access address
1197	ASRELOC(_bsave,%a3)		| no fault!
1198	movl	%a3@,BUSERR
1199	clrl	%d0			| return success
1200	rts
1201ASLOCAL(catchbad)
1202	ASRELOC(_bsave,%a3)		| got a bus error, so restore handler
1203	movl	%a3@,BUSERR
1204	ASRELOC(_ssave,%a3)
1205	movl	%a3@,%sp		| and stack
1206	moveq	#1,%d0			| return fault
1207	rts
1208#undef	BUSERR
1209
1210	.data
1211ASLOCAL(_bsave)
1212	.long   0
1213ASLOCAL(_ssave)
1214	.long   0
1215	.text
1216
1217/*
1218 * Handle the nitty-gritty of rebooting the machine.
1219 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
1220 * Note that we must be running in an address range that is mapped one-to-one
1221 * logical to physical so that the PC is still valid immediately after the MMU
1222 * is turned off.  We have conveniently mapped the last page of physical
1223 * memory this way.
1224 */
1225ENTRY_NOPROFILE(doboot)
1226#if defined(M68040)
1227	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1228	jeq	Lnocache5		| yes, skip
1229#endif
1230	movl	#CACHE_OFF,%d0
1231	movc	%d0,%cacr		| disable on-chip cache(s)
1232	tstl	_C_LABEL(ectype)	| external cache?
1233	jeq	Lnocache5		| no, skip
1234	MMUADDR(%a0)
1235	andl	#~MMU_CEN,%a0@(MMUCMD)	| disable external cache
1236Lnocache5:
1237	lea	MAXADDR,%a0		| last page of physical memory
1238	movl	_C_LABEL(boothowto),%a0@+ | store howto
1239	movl	_C_LABEL(bootdev),%a0@+	| and devtype
1240	lea	Lbootcode,%a1		| start of boot code
1241	lea	Lebootcode,%a3		| end of boot code
1242Lbootcopy:
1243	movw	%a1@+,%a0@+		| copy a word
1244	cmpl	%a3,%a1			| done yet?
1245	jcs	Lbootcopy		| no, keep going
1246#if defined(M68040)
1247	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1248	jne	LmotommuE		| no, skip
1249	.word	0xf4f8			| cpusha bc
1250LmotommuE:
1251#endif
1252	jmp	MAXADDR+8		| jump to last page
1253
1254Lbootcode:
1255	lea	MAXADDR+0x800,%sp	| physical SP in case of NMI
1256#if defined(M68040)
1257	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1258	jne	LmotommuF		| no, skip
1259	movl	#0,%d0
1260	movc	%d0,%cacr		| caches off
1261	.long	0x4e7b0003		| movc %d0,%tc
1262	movl	%d2,MAXADDR+PAGE_SIZE-4	| restore old high page contents
1263	DOREBOOT
1264LmotommuF:
1265#endif
1266#if defined(M68K_MMU_MOTOROLA)
1267	tstl	_C_LABEL(mmutype)	| HP MMU?
1268	jeq	LhpmmuB			| yes, skip
1269	movl	#0,%a0@			| value for pmove to TC (turn off MMU)
1270	pmove	%a0@,%tc		| disable MMU
1271	DOREBOOT
1272LhpmmuB:
1273#endif
1274#if defined(M68K_MMU_HP)
1275	MMUADDR(%a0)
1276	movl	#0xFFFF0000,%a0@(MMUCMD)	| totally disable MMU
1277	movl	%d2,MAXADDR+PAGE_SIZE-4	| restore old high page contents
1278	DOREBOOT
1279#endif
1280Lebootcode:
1281
1282/*
1283 * Misc. global variables.
1284 */
1285	.data
1286GLOBAL(machineid)
1287	.long	HP_320			| default to 320
1288
1289GLOBAL(mmuid)
1290	.long	0			| default to nothing
1291
1292GLOBAL(mmutype)
1293	.long	MMU_HP			| default to HP MMU
1294
1295GLOBAL(cputype)
1296	.long	CPU_68020		| default to 68020 CPU
1297
1298GLOBAL(ectype)
1299	.long	EC_NONE			| external cache type, default to none
1300
1301GLOBAL(fputype)
1302	.long	FPU_68882		| default to 68882 FPU
1303
1304GLOBAL(protorp)
1305	.long	0,0			| prototype root pointer
1306
1307GLOBAL(prototc)
1308	.long	0			| prototype translation control
1309
1310GLOBAL(internalhpib)
1311	.long	1			| has internal HP-IB, default to yes
1312
1313GLOBAL(intiobase)
1314	.long	0			| KVA of base of internal IO space
1315
1316GLOBAL(intiolimit)
1317	.long	0			| KVA of end of internal IO space
1318
1319GLOBAL(extiobase)
1320	.long	0			| KVA of base of external IO space
1321
1322GLOBAL(CLKbase)
1323	.long	0			| KVA of base of clock registers
1324
1325GLOBAL(MMUbase)
1326	.long	0			| KVA of base of HP MMU registers
1327
1328#ifdef USELEDS
1329ASLOCAL(heartbeat)
1330	.long	0			| clock ticks since last heartbeat
1331
1332ASLOCAL(beatstatus)
1333	.long	0			| for determining a fast or slow throb
1334#endif
1335
1336#ifdef DEBUG
1337ASGLOBAL(fulltflush)
1338	.long	0
1339
1340ASGLOBAL(fullcflush)
1341	.long	0
1342#endif
1343