xref: /netbsd/sys/arch/hp300/hp300/locore.s (revision bf9ec67e)
1/*	$NetBSD: locore.s,v 1.121 2002/05/19 21:40:04 jdolecek Exp $	*/
2
3/*
4 * Copyright (c) 1994, 1995 Gordon W. Ross
5 * Copyright (c) 1988 University of Utah.
6 * Copyright (c) 1980, 1990, 1993
7 *	The Regents of the University of California.  All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * the Systems Programming Group of the University of Utah Computer
11 * Science Department.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 *    must display the following acknowledgement:
23 *	This product includes software developed by the University of
24 *	California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 *    may be used to endorse or promote products derived from this software
27 *    without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 * from: Utah $Hdr: locore.s 1.66 92/12/22$
42 *
43 *	@(#)locore.s	8.6 (Berkeley) 5/27/94
44 */
45
46#include "opt_compat_netbsd.h"
47#include "opt_compat_svr4.h"
48#include "opt_compat_sunos.h"
49#include "opt_ddb.h"
50#include "opt_fpsp.h"
51#include "opt_kgdb.h"
52#include "opt_lockdebug.h"
53
54#include "assym.h"
55#include <machine/asm.h>
56#include <machine/trap.h>
57
58#include "opt_useleds.h"
59#ifdef USELEDS
60#include <hp300/hp300/leds.h>
61#endif
62
63#define MMUADDR(ar)	movl	_C_LABEL(MMUbase),ar
64#define CLKADDR(ar)	movl	_C_LABEL(CLKbase),ar
65
66/*
67 * This is for kvm_mkdb, and should be the address of the beginning
68 * of the kernel text segment (not necessarily the same as kernbase).
69 */
70	.text
71GLOBAL(kernel_text)
72
73/*
74 * Clear and skip the first page of text; it will not be mapped at
75 * VA 0.
76 *
77 * The bootloader places the bootinfo in this page, and we allocate
78 * a VA for it and map it in pmap_bootstrap().
79 */
80	.fill	NBPG/4,4,0
81
82/*
83 * Temporary stack for a variety of purposes.
84 * Try and make this the first thing is the data segment so it
85 * is page aligned.  Note that if we overflow here, we run into
86 * our text segment.
87 */
88	.data
89	.space	NBPG
90ASLOCAL(tmpstk)
91
92#include <hp300/hp300/vectors.s>
93
94/*
95 * Macro to relocate a symbol, used before MMU is enabled.
96 */
97#define	_RELOC(var, ar)		\
98	movel	#var,ar;	\
99	addl	%a5,ar
100
101#define	RELOC(var, ar)		_RELOC(_C_LABEL(var), ar)
102#define	ASRELOC(var, ar)	_RELOC(_ASM_LABEL(var), ar)
103
104/*
105 * Final bits of grunt work required to reboot the system.  The MMU
106 * must be disabled when this is invoked.
107 */
108#define DOREBOOT						\
109	/* Jump to REQ_REBOOT */				\
110	jmp	0x1A4;
111
112/*
113 * Initialization
114 *
115 * A4 contains the address of the end of the symtab
116 * A5 contains physical load point from boot
117 * VBR contains zero from ROM.  Exceptions will continue to vector
118 * through ROM until MMU is turned on at which time they will vector
119 * through our table (vectors.s).
120 */
121
122BSS(lowram,4)
123BSS(esym,4)
124
125ASENTRY_NOPROFILE(start)
126	movw	#PSL_HIGHIPL,%sr	| no interrupts
127	ASRELOC(tmpstk, %a0)
128	movl	%a0,%sp			| give ourselves a temporary stack
129	RELOC(esym, %a0)
130#if 1
131	movl	%a4,%a0@		| store end of symbol table
132#else
133	clrl	%a0@			| no symbol table, yet
134#endif
135	RELOC(lowram, %a0)
136	movl	%a5,%a0@		| store start of physical memory
137	movl	#CACHE_OFF,%d0
138	movc	%d0,%cacr		| clear and disable on-chip cache(s)
139
140/* check for internal HP-IB in SYSFLAG */
141	btst	#5,0xfffffed2		| internal HP-IB?
142	jeq	Lhaveihpib		| yes, have HP-IB just continue
143	RELOC(internalhpib, %a0)
144	movl	#0,%a0@			| no, clear associated address
145Lhaveihpib:
146
147	RELOC(boothowto, %a0)		| save reboot flags
148	movl	%d7,%a0@
149	RELOC(bootdev, %a0)		|   and boot device
150	movl	%d6,%a0@
151
152	/*
153	 * All data registers are now free.  All address registers
154	 * except %a5 are free.  %a5 is used by the RELOC() macro,
155	 * and cannot be used until after the MMU is enabled.
156	 */
157
158/* determine our CPU/MMU combo - check for all regardless of kernel config */
159	movl	#INTIOBASE+MMUBASE,%a1
160	movl	#0x200,%d0		| data freeze bit
161	movc	%d0,%cacr		|   only exists on 68030
162	movc	%cacr,%d0		| read it back
163	tstl	%d0			| zero?
164	jeq	Lnot68030		| yes, we have 68020/68040
165
166	/*
167	 * 68030 models
168	 */
169
170	RELOC(mmutype, %a0)		| no, we have 68030
171	movl	#MMU_68030,%a0@		| set to reflect 68030 PMMU
172	RELOC(cputype, %a0)
173	movl	#CPU_68030,%a0@		| and 68030 CPU
174	RELOC(machineid, %a0)
175	movl	#0x80,%a1@(MMUCMD)	| set magic cookie
176	movl	%a1@(MMUCMD),%d0	| read it back
177	btst	#7,%d0			| cookie still on?
178	jeq	Lnot370			| no, 360 or 375
179	movl	#0,%a1@(MMUCMD)		| clear magic cookie
180	movl	%a1@(MMUCMD),%d0	| read it back
181	btst	#7,%d0			| still on?
182	jeq	Lisa370			| no, must be a 370
183	movl	#HP_340,%a0@		| yes, must be a 340
184	jra	Lstart1
185Lnot370:
186	movl	#HP_360,%a0@		| type is at least a 360
187	movl	#0,%a1@(MMUCMD)		| clear magic cookie2
188	movl	%a1@(MMUCMD),%d0	| read it back
189	btst	#16,%d0			| still on?
190	jeq	Lstart1			| no, must be a 360
191	RELOC(mmuid, %a0)		| save MMU ID
192	lsrl	#MMUID_SHIFT,%d0
193	andl	#MMUID_MASK,%d0
194	movl	%d0,%a0@
195	RELOC(machineid, %a0)
196	cmpb	#MMUID_345,%d0		| are we a 345?
197	beq	Lisa345
198	cmpb	#MMUID_375,%d0		| how about a 375?
199	beq	Lisa375
200	movl	#HP_400,%a0@		| must be a 400
201	jra	Lhaspac
202Lisa345:
203	movl	#HP_345,%a0@
204	jra	Lhaspac
205Lisa375:
206	movl	#HP_375,%a0@
207	jra	Lhaspac
208Lisa370:
209	movl	#HP_370,%a0@		| set to 370
210Lhaspac:
211	RELOC(ectype, %a0)
212	movl	#EC_PHYS,%a0@		| also has a physical address cache
213	jra	Lstart1
214
215	/*
216	 * End of 68030 section
217	 */
218
219Lnot68030:
220	bset	#31,%d0			| data cache enable bit
221	movc	%d0,%cacr		|   only exists on 68040
222	movc	%cacr,%d0		| read it back
223	tstl	%d0			| zero?
224	beq	Lis68020		| yes, we have 68020
225	moveq	#0,%d0			| now turn it back off
226	movec	%d0,%cacr		|   before we access any data
227
228	/*
229	 * 68040 models
230	 */
231
232	RELOC(mmutype, %a0)
233	movl	#MMU_68040,%a0@		| with a 68040 MMU
234	RELOC(cputype, %a0)
235	movl	#CPU_68040,%a0@		| and a 68040 CPU
236	RELOC(fputype, %a0)
237	movl	#FPU_68040,%a0@		| ...and FPU
238	RELOC(ectype, %a0)
239	movl	#EC_NONE,%a0@		| and no cache (for now XXX)
240	RELOC(mmuid,%a0)		| save MMU ID
241	movl	%a1@(MMUCMD),%d0
242	lsrl	#MMUID_SHIFT,%d0
243	andl	#MMUID_MASK,%d0
244	movl	%d0,%a0@
245	RELOC(machineid, %a0)
246	cmpb	#MMUID_425_T,%d0	| are we a 425t?
247	jeq	Lisa425
248	cmpb	#MMUID_425_S,%d0	| how about 425s?
249	jeq	Lisa425
250	cmpb	#MMUID_425_E,%d0	| or maybe a 425e?
251	jeq	Lisa425
252	cmpb	#MMUID_433_T,%d0	| or a 433t?
253	jeq	Lisa433
254	cmpb	#MMUID_433_S,%d0	| or a 433s?
255	jeq	Lisa433
256	cmpb	#MMUID_385,%d0		| or a 385?
257	jeq	Lisa385
258	movl	#HP_380,%a0@		| guess we're a 380
259	jra	Lstart1
260Lisa425:
261	movl	#HP_425,%a0@
262	jra	Lstart1
263Lisa433:
264	movl	#HP_433,%a0@
265	jra	Lstart1
266Lisa385:
267	movl	#HP_385,%a0@
268	jra	Lstart1
269
270	/*
271	 * End of 68040 section
272	 */
273
274	/*
275	 * 68020 models
276	 */
277
278Lis68020:
279	RELOC(fputype, %a0)		| all of the 68020 systems
280	movl	#FPU_68881,%a0@		|   have a 68881 FPU
281	movl	#1,%a1@(MMUCMD)		| a 68020, write HP MMU location
282	movl	%a1@(MMUCMD),%d0	| read it back
283	btst	#0,%d0			| non-zero?
284	jne	Lishpmmu		| yes, we have HP MMU
285	RELOC(mmutype, %a0)
286	movl	#MMU_68851,%a0@		| no, we have PMMU
287	RELOC(machineid, %a0)
288	movl	#HP_330,%a0@		| and 330 CPU
289	jra	Lstart1
290Lishpmmu:
291	RELOC(ectype, %a0)		| 320 or 350
292	movl	#EC_VIRT,%a0@		| both have a virtual address cache
293	movl	#0x80,%a1@(MMUCMD)	| set magic cookie
294	movl	%a1@(MMUCMD),%d0	| read it back
295	btst	#7,%d0			| cookie still on?
296	jeq	Lis320			| no, just a 320
297	RELOC(machineid, %a0)
298	movl	#HP_350,%a0@		| yes, a 350
299	jra	Lstart1
300Lis320:
301	RELOC(machineid, %a0)
302	movl	#HP_320,%a0@
303
304	/*
305	 * End of 68020 section
306	 */
307
308Lstart1:
309	/*
310	 * Now that we know what CPU we have, initialize the address error
311	 * and bus error handlers in the vector table:
312	 *
313	 *	vectab+8	bus error
314	 *	vectab+12	address error
315	 */
316	RELOC(cputype, %a0)
317#if 0
318	/* XXX assembler/linker feature/bug */
319	RELOC(vectab, %a2)
320#else
321	movl	#_C_LABEL(vectab),%a2
322	addl	%a5,%a2
323#endif
324#if defined(M68040)
325	cmpl	#CPU_68040,%a0@		| 68040?
326	jne	1f			| no, skip
327	movl	#_C_LABEL(buserr40),%a2@(8)
328	movl	#_C_LABEL(addrerr4060),%a2@(12)
329	jra	Lstart2
3301:
331#endif
332#if defined(M68020) || defined(M68030)
333	cmpl	#CPU_68040,%a0@		| 68040?
334	jeq	1f			| yes, skip
335	movl	#_C_LABEL(busaddrerr2030),%a2@(8)
336	movl	#_C_LABEL(busaddrerr2030),%a2@(12)
337	jra	Lstart2
3381:
339#endif
340	/* Config botch; no hope. */
341	DOREBOOT
342
343Lstart2:
344	movl	#0,%a1@(MMUCMD)		| clear out MMU again
345/* initialize source/destination control registers for movs */
346	moveq	#FC_USERD,%d0		| user space
347	movc	%d0,%sfc		|   as source
348	movc	%d0,%dfc		|   and destination of transfers
349/* initialize memory sizes (for pmap_bootstrap) */
350	movl	#MAXADDR,%d1		| last page
351	moveq	#PGSHIFT,%d2
352	lsrl	%d2,%d1			| convert to page (click) number
353	RELOC(maxmem, %a0)
354	movl	%d1,%a0@		| save as maxmem
355	movl	%a5,%d0			| lowram value from ROM via boot
356	lsrl	%d2,%d0			| convert to page number
357	subl	%d0,%d1			| compute amount of RAM present
358	RELOC(physmem, %a0)
359	movl	%d1,%a0@		| and physmem
360
361/* configure kernel and proc0 VA space so we can get going */
362#ifdef DDB
363	RELOC(esym,%a0)			| end of static kernel test/data/syms
364	movl	%a0@,%d5
365	jne	Lstart3
366#endif
367	movl	#_C_LABEL(end),%d5	| end of static kernel text/data
368Lstart3:
369	addl	#NBPG-1,%d5
370	andl	#PG_FRAME,%d5		| round to a page
371	movl	%d5,%a4
372	addl	%a5,%a4			| convert to PA
373	pea	%a5@			| firstpa
374	pea	%a4@			| nextpa
375	RELOC(pmap_bootstrap,%a0)
376	jbsr	%a0@			| pmap_bootstrap(firstpa, nextpa)
377	addql	#8,%sp
378
379/*
380 * Prepare to enable MMU.
381 * Since the kernel is not mapped logical == physical we must insure
382 * that when the MMU is turned on, all prefetched addresses (including
383 * the PC) are valid.  In order guarentee that, we use the last physical
384 * page (which is conveniently mapped == VA) and load it up with enough
385 * code to defeat the prefetch, then we execute the jump back to here.
386 *
387 * Is this all really necessary, or am I paranoid??
388 */
389	RELOC(Sysseg, %a0)		| system segment table addr
390	movl	%a0@,%d1		| read value (a KVA)
391	addl	%a5,%d1			| convert to PA
392	RELOC(mmutype, %a0)
393	tstl	%a0@			| HP MMU?
394	jeq	Lhpmmu2			| yes, skip
395	cmpl	#MMU_68040,%a0@		| 68040?
396	jne	Lmotommu1		| no, skip
397	.long	0x4e7b1807		| movc %d1,%srp
398	jra	Lstploaddone
399Lmotommu1:
400	RELOC(protorp, %a0)
401	movl	#0x80000202,%a0@	| nolimit + share global + 4 byte PTEs
402	movl	%d1,%a0@(4)		| + segtable address
403	pmove	%a0@,%srp		| load the supervisor root pointer
404	movl	#0x80000002,%a0@	| reinit upper half for CRP loads
405	jra	Lstploaddone		| done
406Lhpmmu2:
407	moveq	#PGSHIFT,%d2
408	lsrl	%d2,%d1			| convert to page frame
409	movl	%d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register
410Lstploaddone:
411	lea	MAXADDR,%a2		| PA of last RAM page
412#if 0
413	ASRELOC(Lhighcode, %a1)		| addr of high code
414	ASRELOC(Lehighcode, %a3)	| end addr
415#else
416	/* don't want pc-relative addressing */
417	.word	0x43f9			| lea Lhighcode, %a1
418	.long	Lhighcode
419	addl	%a5, %a1
420	.word	0x47f9			| lea Lehighcode, %a3
421	.long	Lehighcode
422	addl	%a5, %a3
423#endif
424Lcodecopy:
425	movw	%a1@+,%a2@+		| copy a word
426	cmpl	%a3,%a1			| done yet?
427	jcs	Lcodecopy		| no, keep going
428	jmp	MAXADDR			| go for it!
429
430	/*
431	 * BEGIN MMU TRAMPOLINE.  This section of code is not
432	 * executed in-place.  It's copied to the last page
433	 * of RAM (mapped va == pa) and executed there.
434	 */
435
436Lhighcode:
437	/*
438	 * Set up the vector table, and race to get the MMU
439	 * enabled.
440	 */
441	movl	#_C_LABEL(vectab),%d0	| set Vector Base Register
442	movc	%d0,%vbr
443
444	RELOC(mmutype, %a0)
445	tstl	%a0@			| HP MMU?
446	jeq	Lhpmmu3			| yes, skip
447	cmpl	#MMU_68040,%a0@		| 68040?
448	jne	Lmotommu2		| no, skip
449	movw	#0,INTIOBASE+MMUBASE+MMUCMD+2
450	movw	#MMU_IEN+MMU_CEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD+2
451					| enable FPU and caches
452	moveq	#0,%d0			| ensure TT regs are disabled
453	.long	0x4e7b0004		| movc %d0,%itt0
454	.long	0x4e7b0005		| movc %d0,%itt1
455	.long	0x4e7b0006		| movc %d0,%dtt0
456	.long	0x4e7b0007		| movc %d0,%dtt1
457	.word	0xf4d8			| cinva bc
458	.word	0xf518			| pflusha
459	movl	#0x8000,%d0
460	.long	0x4e7b0003		| movc %d0,%tc
461	movl	#0x80008000,%d0
462	movc	%d0,%cacr		| turn on both caches
463	jmp	Lenab1:l		| forced not be pc-relative
464Lmotommu2:
465	movl	#MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD
466					| enable 68881 and i-cache
467	RELOC(prototc, %a2)
468	movl	#0x82c0aa00,%a2@	| value to load TC with
469	pmove	%a2@,%tc		| load it
470	jmp	Lenab1:l		| forced not be pc-relative
471Lhpmmu3:
472	movl	#0,INTIOBASE+MMUBASE+MMUCMD		| clear external cache
473	movl	#MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD	| turn on MMU
474	jmp	Lenab1:l		| forced not be pc-relative
475Lehighcode:
476
477	/*
478	 * END MMU TRAMPOLINE.  Address register %a5 is now free.
479	 */
480
481/*
482 * Should be running mapped from this point on
483 */
484Lenab1:
485/* select the software page size now */
486	lea	_ASM_LABEL(tmpstk),%sp		| temporary stack
487	jbsr	_C_LABEL(uvm_setpagesize)  	| select software page size
488/* set kernel stack, user SP, and initial pcb */
489	movl	_C_LABEL(proc0paddr),%a1	| get proc0 pcb addr
490	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
491	lea	_C_LABEL(proc0),%a2	| initialize proc0.p_addr so that
492	movl	%a1,%a2@(P_ADDR)	|   we don't deref NULL in trap()
493	movl	#USRSTACK-4,%a2
494	movl	%a2,%usp		| init user SP
495	movl	%a1,_C_LABEL(curpcb)	| proc0 is running
496
497	tstl	_C_LABEL(fputype)	| Have an FPU?
498	jeq	Lenab2			| No, skip.
499	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
500	movl	%a1,%sp@-
501	jbsr	_C_LABEL(m68881_restore) | restore it (does not kill %a1)
502	addql	#4,%sp
503Lenab2:
504/* flush TLB and turn on caches */
505	jbsr	_C_LABEL(TBIA)		| invalidate TLB
506	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
507	jeq	Lnocache0		| yes, cache already on
508	movl	#CACHE_ON,%d0
509	movc	%d0,%cacr		| clear cache(s)
510	tstl	_C_LABEL(ectype)
511	jeq	Lnocache0
512	MMUADDR(%a0)
513	orl	#MMU_CEN,%a0@(MMUCMD)	| turn on external cache
514Lnocache0:
515/* Final setup for call to main(). */
516	jbsr	_C_LABEL(hp300_init)
517
518/*
519 * Create a fake exception frame so that cpu_fork() can copy it.
520 * main() nevers returns; we exit to user mode from a forked process
521 * later on.
522 */
523	clrw	%sp@-			| vector offset/frame type
524	clrl	%sp@-			| PC - filled in by "execve"
525	movw	#PSL_USER,%sp@-		| in user mode
526	clrl	%sp@-			| stack adjust count and padding
527	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
528	lea	_C_LABEL(proc0),%a0	| save pointer to frame
529	movl	%sp,%a0@(P_MD_REGS)	|   in proc0.p_md.md_regs
530
531	jra	_C_LABEL(main)		| main()
532	PANIC("main() returned")
533	/* NOTREACHED */
534
535/*
536 * proc_trampoline: call function in register %a2 with %a3 as an arg
537 * and then rei.
538 */
539GLOBAL(proc_trampoline)
540	movl	%a3,%sp@-		| push function arg
541	jbsr	%a2@			| call function
542	addql	#4,%sp			| pop arg
543	movl	%sp@(FR_SP),%a0		| grab and load
544	movl	%a0,%usp		|   user SP
545	moveml	%sp@+,#0x7FFF		| restore most user regs
546	addql	#8,%sp			| toss SP and stack adjust
547	jra	_ASM_LABEL(rei)		| and return
548
549
550/*
551 * Trap/interrupt vector routines
552 */
553#include <m68k/m68k/trap_subr.s>
554
555	.data
556GLOBAL(m68k_fault_addr)
557	.long	0
558
559#if defined(M68040) || defined(M68060)
560ENTRY_NOPROFILE(addrerr4060)
561	clrl	%sp@-			| stack adjust count
562	moveml	#0xFFFF,%sp@-		| save user registers
563	movl	%usp,%a0		| save the user SP
564	movl	%a0,%sp@(FR_SP)		|   in the savearea
565	movl	%sp@(FR_HW+8),%sp@-
566	clrl	%sp@-			| dummy code
567	movl	#T_ADDRERR,%sp@-		| mark address error
568	jra	_ASM_LABEL(faultstkadj)	| and deal with it
569#endif
570
571#if defined(M68060)
572ENTRY_NOPROFILE(buserr60)
573	clrl	%sp@-			| stack adjust count
574	moveml	#0xFFFF,%sp@-		| save user registers
575	movl	%usp,%a0		| save the user SP
576	movl	%a0,%sp@(FR_SP)		|   in the savearea
577	movel	%sp@(FR_HW+12),%d0	| FSLW
578	btst	#2,%d0			| branch prediction error?
579	jeq	Lnobpe
580	movc	%cacr,%d2
581	orl	#IC60_CABC,%d2		| clear all branch cache entries
582	movc	%d2,%cacr
583	movl	%d0,%d1
584	addql	#1,L60bpe
585	andl	#0x7ffd,%d1
586	jeq	_ASM_LABEL(faultstkadjnotrap2)
587Lnobpe:
588| we need to adjust for misaligned addresses
589	movl	%sp@(FR_HW+8),%d1	| grab VA
590	btst	#27,%d0			| check for mis-aligned access
591	jeq	Lberr3			| no, skip
592	addl	#28,%d1			| yes, get into next page
593					| operand case: 3,
594					| instruction case: 4+12+12
595	andl	#PG_FRAME,%d1           | and truncate
596Lberr3:
597	movl	%d1,%sp@-
598	movl	%d0,%sp@-		| code is FSLW now.
599	andw	#0x1f80,%d0
600	jeq	Lberr60			| it is a bus error
601	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
602	jra	_ASM_LABEL(faultstkadj)	| and deal with it
603Lberr60:
604	tstl	_C_LABEL(nofault)	| catch bus error?
605	jeq	Lisberr			| no, handle as usual
606	movl	%sp@(FR_HW+8+8),_C_LABEL(m68k_fault_addr) | save fault addr
607	movl	_C_LABEL(nofault),%sp@-	| yes,
608	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
609	/* NOTREACHED */
610#endif
611#if defined(M68040)
612ENTRY_NOPROFILE(buserr40)
613	clrl	%sp@-			| stack adjust count
614	moveml	#0xFFFF,%sp@-		| save user registers
615	movl	%usp,%a0		| save the user SP
616	movl	%a0,%sp@(FR_SP)		|   in the savearea
617	movl	%sp@(FR_HW+20),%d1	| get fault address
618	moveq	#0,%d0
619	movw	%sp@(FR_HW+12),%d0	| get SSW
620	btst	#11,%d0			| check for mis-aligned
621	jeq	Lbe1stpg		| no skip
622	addl	#3,%d1			| get into next page
623	andl	#PG_FRAME,%d1		| and truncate
624Lbe1stpg:
625	movl	%d1,%sp@-		| pass fault address.
626	movl	%d0,%sp@-		| pass SSW as code
627	btst	#10,%d0			| test ATC
628	jeq	Lberr40			| it is a bus error
629	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
630	jra	_ASM_LABEL(faultstkadj)	| and deal with it
631Lberr40:
632	tstl	_C_LABEL(nofault)	| catch bus error?
633	jeq	Lisberr			| no, handle as usual
634	movl	%sp@(FR_HW+8+20),_C_LABEL(m68k_fault_addr) | save fault addr
635	movl	_C_LABEL(nofault),%sp@-	| yes,
636	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
637	/* NOTREACHED */
638#endif
639
640#if defined(M68020) || defined(M68030)
641ENTRY_NOPROFILE(busaddrerr2030)
642	clrl	%sp@-			| stack adjust count
643	moveml	#0xFFFF,%sp@-		| save user registers
644	movl	%usp,%a0		| save the user SP
645	movl	%a0,%sp@(FR_SP)		|   in the savearea
646	moveq	#0,%d0
647	movw	%sp@(FR_HW+10),%d0	| grab SSW for fault processing
648	btst	#12,%d0			| RB set?
649	jeq	LbeX0			| no, test RC
650	bset	#14,%d0			| yes, must set FB
651	movw	%d0,%sp@(FR_HW+10)	| for hardware too
652LbeX0:
653	btst	#13,%d0			| RC set?
654	jeq	LbeX1			| no, skip
655	bset	#15,%d0			| yes, must set FC
656	movw	%d0,%sp@(FR_HW+10)	| for hardware too
657LbeX1:
658	btst	#8,%d0			| data fault?
659	jeq	Lbe0			| no, check for hard cases
660	movl	%sp@(FR_HW+16),%d1	| fault address is as given in frame
661	jra	Lbe10			| thats it
662Lbe0:
663	btst	#4,%sp@(FR_HW+6)	| long (type B) stack frame?
664	jne	Lbe4			| yes, go handle
665	movl	%sp@(FR_HW+2),%d1	| no, can use save PC
666	btst	#14,%d0			| FB set?
667	jeq	Lbe3			| no, try FC
668	addql	#4,%d1			| yes, adjust address
669	jra	Lbe10			| done
670Lbe3:
671	btst	#15,%d0			| FC set?
672	jeq	Lbe10			| no, done
673	addql	#2,%d1			| yes, adjust address
674	jra	Lbe10			| done
675Lbe4:
676	movl	%sp@(FR_HW+36),%d1	| long format, use stage B address
677	btst	#15,%d0			| FC set?
678	jeq	Lbe10			| no, all done
679	subql	#2,%d1			| yes, adjust address
680Lbe10:
681	movl	%d1,%sp@-		| push fault VA
682	movl	%d0,%sp@-		| and padded SSW
683	movw	%sp@(FR_HW+8+6),%d0	| get frame format/vector offset
684	andw	#0x0FFF,%d0		| clear out frame format
685	cmpw	#12,%d0			| address error vector?
686	jeq	Lisaerr			| yes, go to it
687#if defined(M68K_MMU_MOTOROLA)
688#if defined(M68K_MMU_HP)
689	tstl	_C_LABEL(mmutype)	| HP MMU?
690	jeq	Lbehpmmu		| yes, different MMU fault handler
691#endif
692	movl	%d1,%a0			| fault address
693	movl	%sp@,%d0		| function code from ssw
694	btst	#8,%d0			| data fault?
695	jne	Lbe10a
696	movql	#1,%d0			| user program access FC
697					| (we dont separate data/program)
698	btst	#5,%sp@(FR_HW+8)	| supervisor mode?
699	jeq	Lbe10a			| if no, done
700	movql	#5,%d0			| else supervisor program access
701Lbe10a:
702	ptestr	%d0,%a0@,#7		| do a table search
703	pmove	%psr,%sp@		| save result
704	movb	%sp@,%d1
705	btst	#2,%d1			| invalid (incl. limit viol. and berr)?
706	jeq	Lmightnotbemerr		| no -> wp check
707	btst	#7,%d1			| is it MMU table berr?
708	jne	Lisberr1		| yes, needs not be fast.
709#endif /* M68K_MMU_MOTOROLA */
710Lismerr:
711	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
712	jra	_ASM_LABEL(faultstkadj)	| and deal with it
713#if defined(M68K_MMU_MOTOROLA)
714Lmightnotbemerr:
715	btst	#3,%d1			| write protect bit set?
716	jeq	Lisberr1		| no: must be bus error
717	movl	%sp@,%d0			| ssw into low word of %d0
718	andw	#0xc0,%d0		| Write protect is set on page:
719	cmpw	#0x40,%d0		| was it read cycle?
720	jne	Lismerr			| no, was not WPE, must be MMU fault
721	jra	Lisberr1		| real bus err needs not be fast.
722#endif /* M68K_MMU_MOTOROLA */
723#if defined(M68K_MMU_HP)
724Lbehpmmu:
725	MMUADDR(%a0)
726	movl	%a0@(MMUSTAT),%d0	| read MMU status
727	btst	#3,%d0			| MMU fault?
728	jeq	Lisberr1		| no, just a non-MMU bus error
729	andl	#~MMU_FAULT,%a0@(MMUSTAT)| yes, clear fault bits
730	movw	%d0,%sp@		| pass MMU stat in upper half of code
731	jra	Lismerr			| and handle it
732#endif
733Lisaerr:
734	movl	#T_ADDRERR,%sp@-	| mark address error
735	jra	_ASM_LABEL(faultstkadj)	| and deal with it
736Lisberr1:
737	clrw	%sp@			| re-clear pad word
738	tstl	_C_LABEL(nofault)	| catch bus error?
739	jeq	Lisberr			| no, handle as usual
740	movl	%sp@(FR_HW+8+16),_C_LABEL(m68k_fault_addr) | save fault addr
741	movl	_C_LABEL(nofault),%sp@-	| yes,
742	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
743	/* NOTREACHED */
744#endif /* M68020 || M68030 */
745
746Lisberr:				| also used by M68040/60
747	movl	#T_BUSERR,%sp@-		| mark bus error
748	jra	_ASM_LABEL(faultstkadj)	| and deal with it
749
750/*
751 * FP exceptions.
752 */
753ENTRY_NOPROFILE(fpfline)
754#if defined(M68040)
755	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
756	jne	Lfp_unimp		| no, skip FPSP
757	cmpw	#0x202c,%sp@(6)		| format type 2?
758	jne	_C_LABEL(illinst)	| no, not an FP emulation
759Ldofp_unimp:
760#ifdef FPSP
761	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
762#endif
763Lfp_unimp:
764#endif /* M68040 */
765#ifdef FPU_EMULATE
766	clrl	%sp@-			| stack adjust count
767	moveml	#0xFFFF,%sp@-		| save registers
768	moveq	#T_FPEMULI,%d0		| denote as FP emulation trap
769	jra	_ASM_LABEL(fault)	| do it
770#else
771	jra	_C_LABEL(illinst)
772#endif
773
774ENTRY_NOPROFILE(fpunsupp)
775#if defined(M68040)
776	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
777	jne	_C_LABEL(illinst)	| no, treat as illinst
778#ifdef FPSP
779	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
780#endif
781Lfp_unsupp:
782#endif /* M68040 */
783#ifdef FPU_EMULATE
784	clrl	%sp@-			| stack adjust count
785	moveml	#0xFFFF,%sp@-		| save registers
786	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
787	jra	_ASM_LABEL(fault)	| do it
788#else
789	jra	_C_LABEL(illinst)
790#endif
791
792/*
793 * Handles all other FP coprocessor exceptions.
794 * Note that since some FP exceptions generate mid-instruction frames
795 * and may cause signal delivery, we need to test for stack adjustment
796 * after the trap call.
797 */
798ENTRY_NOPROFILE(fpfault)
799	clrl	%sp@-			| stack adjust count
800	moveml	#0xFFFF,%sp@-		| save user registers
801	movl	%usp,%a0		| and save
802	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
803	clrl	%sp@-			| no VA arg
804	movl	_C_LABEL(curpcb),%a0	| current pcb
805	lea	%a0@(PCB_FPCTX),%a0	| address of FP savearea
806	fsave	%a0@			| save state
807#if defined(M68040) || defined(M68060)
808	/* always null state frame on 68040, 68060 */
809	cmpl	#FPU_68040,_C_LABEL(fputype)
810	jle	Lfptnull
811#endif
812	tstb	%a0@			| null state frame?
813	jeq	Lfptnull		| yes, safe
814	clrw	%d0			| no, need to tweak BIU
815	movb	%a0@(1),%d0		| get frame size
816	bset	#3,%a0@(0,%d0:w)	| set exc_pend bit of BIU
817Lfptnull:
818	fmovem	%fpsr,%sp@-		| push %fpsr as code argument
819	frestore %a0@			| restore state
820	movl	#T_FPERR,%sp@-		| push type arg
821	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
822
823/*
824 * Other exceptions only cause four and six word stack frame and require
825 * no post-trap stack adjustment.
826 */
827
828ENTRY_NOPROFILE(badtrap)
829	moveml	#0xC0C0,%sp@-		| save scratch regs
830	movw	%sp@(22),%sp@-		| push exception vector info
831	clrw	%sp@-
832	movl	%sp@(22),%sp@-		| and PC
833	jbsr	_C_LABEL(straytrap)	| report
834	addql	#8,%sp			| pop args
835	moveml	%sp@+,#0x0303		| restore regs
836	jra	_ASM_LABEL(rei)		| all done
837
838ENTRY_NOPROFILE(trap0)
839	clrl	%sp@-			| stack adjust count
840	moveml	#0xFFFF,%sp@-		| save user registers
841	movl	%usp,%a0		| save the user SP
842	movl	%a0,%sp@(FR_SP)		|   in the savearea
843	movl	%d0,%sp@-		| push syscall number
844	jbsr	_C_LABEL(syscall)	| handle it
845	addql	#4,%sp			| pop syscall arg
846	tstl	_C_LABEL(astpending)
847	jne	Lrei2
848	tstb	_C_LABEL(ssir)
849	jeq	Ltrap1
850	movw	#SPL1,%sr
851	tstb	_C_LABEL(ssir)
852	jne	Lsir1
853Ltrap1:
854	movl	%sp@(FR_SP),%a0		| grab and restore
855	movl	%a0,%usp			|   user SP
856	moveml	%sp@+,#0x7FFF		| restore most registers
857	addql	#8,%sp			| pop SP and stack adjust
858	rte
859
860/*
861 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
862 *	cachectl(command, addr, length)
863 * command in %d0, addr in %a1, length in %d1
864 */
865ENTRY_NOPROFILE(trap12)
866	movl	_C_LABEL(curproc),%sp@-	| push current proc pointer
867	movl	%d1,%sp@-		| push length
868	movl	%a1,%sp@-		| push addr
869	movl	%d0,%sp@-		| push command
870	jbsr	_C_LABEL(cachectl1)	| do it
871	lea	%sp@(16),%sp		| pop args
872	jra	_ASM_LABEL(rei)		| all done
873
874/*
875 * Trace (single-step) trap.  Kernel-mode is special.
876 * User mode traps are simply passed on to trap().
877 */
878ENTRY_NOPROFILE(trace)
879	clrl	%sp@-			| stack adjust count
880	moveml	#0xFFFF,%sp@-
881	moveq	#T_TRACE,%d0
882
883	| Check PSW and see what happen.
884	|   T=0 S=0	(should not happen)
885	|   T=1 S=0	trace trap from user mode
886	|   T=0 S=1	trace trap on a trap instruction
887	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
888
889	movw	%sp@(FR_HW),%d1		| get PSW
890	notw	%d1			| XXX no support for T0 on 680[234]0
891	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
892	jeq	Lkbrkpt			| yes, kernel breakpoint
893	jra	_ASM_LABEL(fault)	| no, user-mode fault
894
895/*
896 * Trap 15 is used for:
897 *	- GDB breakpoints (in user programs)
898 *	- KGDB breakpoints (in the kernel)
899 *	- trace traps for SUN binaries (not fully supported yet)
900 * User mode traps are simply passed to trap().
901 */
902ENTRY_NOPROFILE(trap15)
903	clrl	%sp@-			| stack adjust count
904	moveml	#0xFFFF,%sp@-
905	moveq	#T_TRAP15,%d0
906	movw	%sp@(FR_HW),%d1		| get PSW
907	andw	#PSL_S,%d1		| from system mode?
908	jne	Lkbrkpt			| yes, kernel breakpoint
909	jra	_ASM_LABEL(fault)	| no, user-mode fault
910
911Lkbrkpt: | Kernel-mode breakpoint or trace trap. (%d0=trap_type)
912	| Save the system sp rather than the user sp.
913	movw	#PSL_HIGHIPL,%sr	| lock out interrupts
914	lea	%sp@(FR_SIZE),%a6	| Save stack pointer
915	movl	%a6,%sp@(FR_SP)		|  from before trap
916
917	| If were are not on tmpstk switch to it.
918	| (so debugger can change the stack pointer)
919	movl	%a6,%d1
920	cmpl	#_ASM_LABEL(tmpstk),%d1
921	jls	Lbrkpt2			| already on tmpstk
922	| Copy frame to the temporary stack
923	movl	%sp,%a0			| %a0=src
924	lea	_ASM_LABEL(tmpstk)-96,%a1 | a1=dst
925	movl	%a1,%sp			| %sp=new frame
926	moveq	#FR_SIZE,%d1
927Lbrkpt1:
928	movl	%a0@+,%a1@+
929	subql	#4,%d1
930	bgt	Lbrkpt1
931
932Lbrkpt2:
933	| Call the trap handler for the kernel debugger.
934	| Do not call trap() to do it, so that we can
935	| set breakpoints in trap() if we want.  We know
936	| the trap type is either T_TRACE or T_BREAKPOINT.
937	| If we have both DDB and KGDB, let KGDB see it first,
938	| because KGDB will just return 0 if not connected.
939	| Save args in %d2, %a2
940	movl	%d0,%d2			| trap type
941	movl	%sp,%a2			| frame ptr
942#ifdef KGDB
943	| Let KGDB handle it (if connected)
944	movl	%a2,%sp@-		| push frame ptr
945	movl	%d2,%sp@-		| push trap type
946	jbsr	_C_LABEL(kgdb_trap)	| handle the trap
947	addql	#8,%sp			| pop args
948	cmpl	#0,%d0			| did kgdb handle it?
949	jne	Lbrkpt3			| yes, done
950#endif
951#ifdef DDB
952	| Let DDB handle it
953	movl	%a2,%sp@-		| push frame ptr
954	movl	%d2,%sp@-		| push trap type
955	jbsr	_C_LABEL(kdb_trap)	| handle the trap
956	addql	#8,%sp			| pop args
957#if 0	/* not needed on hp300 */
958	cmpl	#0,%d0			| did ddb handle it?
959	jne	Lbrkpt3			| yes, done
960#endif
961#endif
962	/* Sun 3 drops into PROM here. */
963Lbrkpt3:
964	| The stack pointer may have been modified, or
965	| data below it modified (by kgdb push call),
966	| so push the hardware frame at the current sp
967	| before restoring registers and returning.
968
969	movl	%sp@(FR_SP),%a0		| modified %sp
970	lea	%sp@(FR_SIZE),%a1	| end of our frame
971	movl	%a1@-,%a0@-		| copy 2 longs with
972	movl	%a1@-,%a0@-		| ... predecrement
973	movl	%a0,%sp@(FR_SP)		| %sp = h/w frame
974	moveml	%sp@+,#0x7FFF		| restore all but %sp
975	movl	%sp@,%sp		| ... and %sp
976	rte				| all done
977
978/* Use common m68k sigreturn */
979#include <m68k/m68k/sigreturn.s>
980
981/*
982 * Interrupt handlers.
983 * All device interrupts are auto-vectored.  The CPU provides
984 * the vector 0x18+level.  Note we count spurious interrupts, but
985 * we don't do anything else with them.
986 */
987
988#define INTERRUPT_SAVEREG	moveml	#0xC0C0,%sp@-
989#define INTERRUPT_RESTOREREG	moveml	%sp@+,#0x0303
990
991/* 64-bit evcnt counter increments */
992#define EVCNT_COUNTER(ipl)					\
993	_C_LABEL(hp300_intr_list) + (ipl)*SIZEOF_HI + HI_EVCNT
994#define EVCNT_INCREMENT(ipl)					\
995	movel	%d2,-(%sp);					\
996	clrl	%d0;						\
997	moveql	#1,%d1;						\
998	addl	%d1,EVCNT_COUNTER(ipl)+4;			\
999	movel	EVCNT_COUNTER(ipl),%d2;				\
1000	addxl	%d0,%d2;					\
1001	movel	%d2,EVCNT_COUNTER(ipl);				\
1002	movel	(%sp)+,%d2
1003
1004ENTRY_NOPROFILE(spurintr)	/* level 0 */
1005	EVCNT_INCREMENT(0)
1006	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
1007	jra	_ASM_LABEL(rei)
1008
1009ENTRY_NOPROFILE(intrhand)	/* levels 1 through 5 */
1010	INTERRUPT_SAVEREG
1011	movw	%sp@(22),%sp@-		| push exception vector info
1012	clrw	%sp@-
1013	jbsr	_C_LABEL(intr_dispatch)	| call dispatch routine
1014	addql	#4,%sp
1015	INTERRUPT_RESTOREREG
1016	jra	_ASM_LABEL(rei)		| all done
1017
1018ENTRY_NOPROFILE(lev6intr)	/* level 6: clock */
1019	INTERRUPT_SAVEREG
1020	CLKADDR(%a0)
1021	movb	%a0@(CLKSR),%d0		| read clock status
1022Lclkagain:
1023	btst	#0,%d0			| clear timer1 int immediately to
1024	jeq	Lnotim1			|  minimize chance of losing another
1025	movpw	%a0@(CLKMSB1),%d1	|  due to statintr processing delay
1026Lnotim1:
1027	btst	#2,%d0			| timer3 interrupt?
1028	jeq	Lnotim3			| no, skip statclock
1029	movpw	%a0@(CLKMSB3),%d1	| clear timer3 interrupt
1030	lea	%sp@(16),%a1		| a1 = &clockframe
1031	movl	%d0,%sp@-		| save status
1032	movl	%a1,%sp@-
1033	jbsr	_C_LABEL(statintr)	| statintr(&frame)
1034	addql	#4,%sp
1035	movl	%sp@+,%d0		| restore pre-statintr status
1036	CLKADDR(%a0)
1037Lnotim3:
1038	btst	#0,%d0			| timer1 interrupt?
1039	jeq	Lrecheck		| no, skip hardclock
1040	EVCNT_INCREMENT(6)
1041	lea	%sp@(16),%a1		| a1 = &clockframe
1042	movl	%a1,%sp@-
1043#ifdef USELEDS
1044	tstl	_C_LABEL(ledaddr)	| using LEDs?
1045	jeq	Lnoleds0		| no, skip this code
1046	movl	_ASM_LABEL(heartbeat),%d0 | get tick count
1047	addql	#1,%d0			|  increment
1048	movl	_C_LABEL(hz),%d1
1049	addl	#50,%d1			| get the timing a little closer
1050	tstb	_ASM_LABEL(beatstatus)	| time to slow down?
1051	jeq	Lslowthrob		| yes, slow down
1052	lsrl	#3,%d1			| no, fast throb
1053Lslowthrob:
1054	lsrl	#1,%d1			| slow throb
1055	cmpl	%d0,%d1			| are we there yet?
1056	jne	Lnoleds1		| no, nothing to do
1057	addqb	#1,_ASM_LABEL(beatstatus) | incr beat status
1058	cmpb	#3,_ASM_LABEL(beatstatus) | time to reset?
1059	jle	Ltwinkle		  | no, twinkle the lights
1060	movb	#0,_ASM_LABEL(beatstatus) | reset the status indicator
1061Ltwinkle:
1062	movl	#LED_PULSE,%sp@-
1063	movl	#LED_DISK+LED_LANRCV+LED_LANXMT,%sp@-
1064	clrl	%sp@-
1065	jbsr	_C_LABEL(ledcontrol)	| toggle pulse, turn all others off
1066	lea	%sp@(12),%sp
1067	movql	#0,%d0
1068Lnoleds1:
1069	movl	%d0,_ASM_LABEL(heartbeat)
1070Lnoleds0:
1071#endif /* USELEDS */
1072	jbsr	_C_LABEL(hardclock)	| hardclock(&frame)
1073	addql	#4,%sp
1074	CLKADDR(%a0)
1075Lrecheck:
1076	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS | chalk up another interrupt
1077	movb	%a0@(CLKSR),%d0		| see if anything happened
1078	jmi	Lclkagain		|  while we were in hardclock/statintr
1079	INTERRUPT_RESTOREREG
1080	jra	_ASM_LABEL(rei)		| all done
1081
1082ENTRY_NOPROFILE(lev7intr)	/* level 7: parity errors, reset key */
1083	EVCNT_INCREMENT(7)
1084	clrl	%sp@-
1085	moveml	#0xFFFF,%sp@-		| save registers
1086	movl	%usp,%a0		| and save
1087	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
1088	jbsr	_C_LABEL(nmihand)	| call handler
1089	movl	%sp@(FR_SP),%a0		| restore
1090	movl	%a0,%usp		|   user SP
1091	moveml	%sp@+,#0x7FFF		| and remaining registers
1092	addql	#8,%sp			| pop SP and stack adjust
1093	jra	_ASM_LABEL(rei)		| all done
1094
1095/*
1096 * Emulation of VAX REI instruction.
1097 *
1098 * This code deals with checking for and servicing ASTs (profiling,
1099 * scheduling) and software interrupts.  We check for ASTs first, just
1100 * like the VAX.  After identifing that we need an AST we
1101 * drop the IPL to allow device interrupts.
1102 *
1103 * This code is complicated by the fact that sendsig may have been called
1104 * necessitating a stack cleanup.
1105 */
1106
1107ASENTRY_NOPROFILE(rei)
1108	tstl	_C_LABEL(astpending)	| AST pending?
1109	jeq	Lchksir			| no, go check for SIR
1110Lrei1:
1111	btst	#5,%sp@			| yes, are we returning to user mode?
1112	jne	Lchksir			| no, go check for SIR
1113	movw	#PSL_LOWIPL,%sr		| lower SPL
1114	clrl	%sp@-			| stack adjust
1115	moveml	#0xFFFF,%sp@-		| save all registers
1116	movl	%usp,%a1		| including
1117	movl	%a1,%sp@(FR_SP)		|    the users SP
1118Lrei2:
1119	clrl	%sp@-			| VA == none
1120	clrl	%sp@-			| code == none
1121	movl	#T_ASTFLT,%sp@-		| type == async system trap
1122	jbsr	_C_LABEL(trap)		| go handle it
1123	lea	%sp@(12),%sp		| pop value args
1124	movl	%sp@(FR_SP),%a0		| restore user SP
1125	movl	%a0,%usp		|   from save area
1126	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
1127	jne	Laststkadj		| yes, go to it
1128	moveml	%sp@+,#0x7FFF		| no, restore most user regs
1129	addql	#8,%sp			| toss SP and stack adjust
1130	rte				| and do real RTE
1131Laststkadj:
1132	lea	%sp@(FR_HW),%a1		| pointer to HW frame
1133	addql	#8,%a1			| source pointer
1134	movl	%a1,%a0			| source
1135	addw	%d0,%a0			|  + hole size = dest pointer
1136	movl	%a1@-,%a0@-		| copy
1137	movl	%a1@-,%a0@-		|  8 bytes
1138	movl	%a0,%sp@(FR_SP)		| new SSP
1139	moveml	%sp@+,#0x7FFF		| restore user registers
1140	movl	%sp@,%sp		| and our SP
1141	rte				| and do real RTE
1142Lchksir:
1143	tstb	_C_LABEL(ssir)		| SIR pending?
1144	jeq	Ldorte			| no, all done
1145	movl	%d0,%sp@-		| need a scratch register
1146	movw	%sp@(4),%d0		| get SR
1147	andw	#PSL_IPL7,%d0		| mask all but IPL
1148	jne	Lnosir			| came from interrupt, no can do
1149	movl	%sp@+,%d0		| restore scratch register
1150Lgotsir:
1151	movw	#SPL1,%sr		| prevent others from servicing int
1152	tstb	_C_LABEL(ssir)		| too late?
1153	jeq	Ldorte			| yes, oh well...
1154	clrl	%sp@-			| stack adjust
1155	moveml	#0xFFFF,%sp@-		| save all registers
1156	movl	%usp,%a1		| including
1157	movl	%a1,%sp@(FR_SP)		|    the users SP
1158Lsir1:
1159	clrl	%sp@-			| VA == none
1160	clrl	%sp@-			| code == none
1161	movl	#T_SSIR,%sp@-		| type == software interrupt
1162	jbsr	_C_LABEL(trap)		| go handle it
1163	lea	%sp@(12),%sp		| pop value args
1164	movl	%sp@(FR_SP),%a0		| restore
1165	movl	%a0,%usp		|   user SP
1166	moveml	%sp@+,#0x7FFF		| and all remaining registers
1167	addql	#8,%sp			| pop SP and stack adjust
1168	rte
1169Lnosir:
1170	movl	%sp@+,%d0		| restore scratch register
1171Ldorte:
1172	rte				| real return
1173
1174/*
1175 * Use common m68k sigcode.
1176 */
1177#include <m68k/m68k/sigcode.s>
1178#ifdef COMPAT_SUNOS
1179#include <m68k/m68k/sunos_sigcode.s>
1180#endif
1181#ifdef COMPAT_SVR4
1182#include <m68k/m68k/svr4_sigcode.s>
1183#endif
1184
1185/*
1186 * Primitives
1187 */
1188
1189/*
1190 * Use common m68k support routines.
1191 */
1192#include <m68k/m68k/support.s>
1193
1194/*
1195 * Use common m68k process manipulation routines.
1196 */
1197#include <m68k/m68k/proc_subr.s>
1198
1199	.data
1200GLOBAL(curpcb)
1201GLOBAL(masterpaddr)			| XXX compatibility (debuggers)
1202	.long	0
1203
1204ASLOCAL(mdpflag)
1205	.byte	0			| copy of proc md_flags low byte
1206#ifdef __ELF__
1207	.align	4
1208#else
1209	.align	2
1210#endif
1211
1212ASBSS(nullpcb,SIZEOF_PCB)
1213
1214/*
1215 * At exit of a process, do a switch for the last time.
1216 * Switch to a safe stack and PCB, and select a new process to run.  The
1217 * old stack and u-area will be freed by the reaper.
1218 *
1219 * MUST BE CALLED AT SPLHIGH!
1220 */
1221ENTRY(switch_exit)
1222	movl	%sp@(4),%a0
1223	/* save state into garbage pcb */
1224	movl	#_ASM_LABEL(nullpcb),_C_LABEL(curpcb)
1225	lea	_ASM_LABEL(tmpstk),%sp	| goto a tmp stack
1226
1227	/* Schedule the vmspace and stack to be freed. */
1228	movl	%a0,%sp@-		| exit2(p)
1229	jbsr	_C_LABEL(exit2)
1230	lea	%sp@(4),%sp		| pop args
1231
1232#if defined(LOCKDEBUG)
1233	/* Acquire sched_lock */
1234	jbsr	_C_LABEL(sched_lock_idle)
1235#endif
1236
1237	jra	_C_LABEL(cpu_switch)
1238
1239/*
1240 * When no processes are on the runq, Swtch branches to Idle
1241 * to wait for something to come ready.
1242 */
1243ASENTRY_NOPROFILE(Idle)
1244#if defined(LOCKDEBUG)
1245	/* Release sched_lock */
1246	jbsr	_C_LABEL(sched_unlock_idle)
1247#endif
1248	stop	#PSL_LOWIPL
1249	movw	#PSL_HIGHIPL,%sr
1250#if defined(LOCKDEBUG)
1251	/* Acquire sched_lock */
1252	jbsr	_C_LABEL(sched_lock_idle)
1253#endif
1254	movl	_C_LABEL(sched_whichqs),%d0
1255	jeq	_ASM_LABEL(Idle)
1256	jra	Lsw1
1257
1258Lbadsw:
1259	PANIC("switch")
1260	/*NOTREACHED*/
1261
1262/*
1263 * cpu_switch()
1264 *
1265 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
1266 * entire ATC.  The effort involved in selective flushing may not be
1267 * worth it, maybe we should just flush the whole thing?
1268 *
1269 * NOTE 2: With the new VM layout we now no longer know if an inactive
1270 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1271 * bit).  For now, we just always flush the full ATC.
1272 */
1273ENTRY(cpu_switch)
1274	movl	_C_LABEL(curpcb),%a0	| current pcb
1275	movw	%sr,%a0@(PCB_PS)	| save %sr before changing ipl
1276#ifdef notyet
1277	movl	_C_LABEL(curproc),%sp@-	| remember last proc running
1278#endif
1279	clrl	_C_LABEL(curproc)
1280
1281	/*
1282	 * Find the highest-priority queue that isn't empty,
1283	 * then take the first proc from that queue.
1284	 */
1285	movl	_C_LABEL(sched_whichqs),%d0
1286	jeq	_ASM_LABEL(Idle)
1287Lsw1:
1288	/*
1289	 * Interrupts are blocked, sched_lock is held.  If
1290	 * we come here via Idle, %d0 contains the contents
1291	 * of a non-zero sched_whichqs.
1292	 */
1293	movl	%d0,%d1
1294	negl	%d0
1295	andl	%d1,%d0
1296	bfffo	%d0{#0:#32},%d1
1297	eorib	#31,%d1
1298
1299	movl	%d1,%d0
1300	lslb	#3,%d1			| convert queue number to index
1301	addl	#_C_LABEL(sched_qs),%d1	| locate queue (q)
1302	movl	%d1,%a1
1303	movl	%a1@(P_FORW),%a0	| p = q->p_forw
1304	cmpal	%d1,%a0			| anyone on queue?
1305	jeq	Lbadsw			| no, panic
1306#ifdef DIAGNOSTIC
1307	tstl	%a0@(P_WCHAN)
1308	jne	Lbadsw
1309	cmpb	#SRUN,%a0@(P_STAT)
1310	jne	Lbadsw
1311#endif
1312	movl	%a0@(P_FORW),%a1@(P_FORW)	| q->p_forw = p->p_forw
1313	movl	%a0@(P_FORW),%a1	| n = p->p_forw
1314	movl	%d1,%a1@(P_BACK)	| n->p_back = q
1315	cmpal	%d1,%a1			| anyone left on queue?
1316	jne	Lsw2			| yes, skip
1317	movl	_C_LABEL(sched_whichqs),%d1
1318	bclr	%d0,%d1			| no, clear bit
1319	movl	%d1,_C_LABEL(sched_whichqs)
1320Lsw2:
1321	/* p->p_cpu initialized in fork1() for single-processor */
1322	movb	#SONPROC,%a0@(P_STAT)	| p->p_stat = SONPROC
1323	movl	%a0,_C_LABEL(curproc)
1324	clrl	_C_LABEL(want_resched)
1325#ifdef notyet
1326	movl	%sp@+,%a1
1327	cmpl	%a0,%a1			| switching to same proc?
1328	jeq	Lswdone			| yes, skip save and restore
1329#endif
1330	/*
1331	 * Save state of previous process in its pcb.
1332	 */
1333	movl	_C_LABEL(curpcb),%a1
1334	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
1335	movl	%usp,%a2		| grab USP (%a2 has been saved)
1336	movl	%a2,%a1@(PCB_USP)	| and save it
1337
1338	tstl	_C_LABEL(fputype)	| Do we have an FPU?
1339	jeq	Lswnofpsave		| No  Then don't attempt save.
1340	lea	%a1@(PCB_FPCTX),%a2	| pointer to FP save area
1341	fsave	%a2@			| save FP state
1342	tstb	%a2@			| null state frame?
1343	jeq	Lswnofpsave		| yes, all done
1344	fmovem	%fp0-%fp7,%a2@(FPF_REGS) | save FP general registers
1345	fmovem	%fpcr/%fpsr/%fpi,%a2@(FPF_FPCR)	| save FP control registers
1346Lswnofpsave:
1347
1348	clrl	%a0@(P_BACK)		| clear back link
1349	movb	%a0@(P_MD_FLAGS+3),mdpflag | low byte of p_md.md_flags
1350	movl	%a0@(P_ADDR),%a1	| get p_addr
1351	movl	%a1,_C_LABEL(curpcb)
1352
1353#if defined(LOCKDEBUG)
1354	/*
1355	 * Done mucking with the run queues, release the
1356	 * scheduler lock, but keep interrupts out.
1357	 */
1358	movl	%a0,sp@-		| not args...
1359	movl	%a1,sp@-		| ...just saving
1360	jbsr	_C_LABEL(sched_unlock_idle)
1361	movl	sp@+,%a1
1362	movl	sp@+,%a0
1363#endif
1364
1365	/*
1366	 * Activate process's address space.
1367	 * XXX Should remember the last USTP value loaded, and call this
1368	 * XXX only if it has changed.
1369	 */
1370	pea	%a0@			| push proc
1371	jbsr	_C_LABEL(pmap_activate)	| pmap_activate(p)
1372	addql	#4,%sp
1373	movl	_C_LABEL(curpcb),%a1	| restore p_addr
1374
1375	lea	_ASM_LABEL(tmpstk),%sp	| now goto a tmp stack for NMI
1376
1377	moveml	%a1@(PCB_REGS),#0xFCFC	| and registers
1378	movl	%a1@(PCB_USP),%a0
1379	movl	%a0,%usp		| and USP
1380
1381	tstl	_C_LABEL(fputype)	| If we don't have an FPU,
1382	jeq	Lnofprest		|  don't try to restore it.
1383	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
1384	tstb	%a0@			| null state frame?
1385	jeq	Lresfprest		| yes, easy
1386#if defined(M68040)
1387#if defined(M68020) || defined(M68030)
1388	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1389	jne	Lresnot040		| no, skip
1390#endif
1391	clrl	%sp@-			| yes...
1392	frestore %sp@+			| ...magic!
1393Lresnot040:
1394#endif
1395	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi	| restore FP control registers
1396	fmovem	%a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers
1397Lresfprest:
1398	frestore %a0@			| restore state
1399
1400Lnofprest:
1401	movw	%a1@(PCB_PS),%sr	| no, restore PS
1402	moveq	#1,%d0			| return 1 (for alternate returns)
1403	rts
1404
1405/*
1406 * savectx(pcb)
1407 * Update pcb, saving current processor state.
1408 */
1409ENTRY(savectx)
1410	movl	%sp@(4),%a1
1411	movw	%sr,%a1@(PCB_PS)
1412	movl	%usp,%a0		| grab USP
1413	movl	%a0,%a1@(PCB_USP)	| and save it
1414	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
1415
1416	tstl	_C_LABEL(fputype)	| Do we have FPU?
1417	jeq	Lsvnofpsave		| No?  Then don't save state.
1418	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
1419	fsave	%a0@			| save FP state
1420	tstb	%a0@			| null state frame?
1421	jeq	Lsvnofpsave		| yes, all done
1422	fmovem	%fp0-%fp7,%a0@(FPF_REGS) | save FP general registers
1423	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR)	| save FP control registers
1424Lsvnofpsave:
1425	moveq	#0,%d0			| return 0
1426	rts
1427
1428#if defined(M68040)
1429ENTRY(suline)
1430	movl	%sp@(4),%a0		| address to write
1431	movl	_C_LABEL(curpcb),%a1	| current pcb
1432	movl	#Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault
1433	movl	%sp@(8),%a1		| address of line
1434	movl	%a1@+,%d0		| get lword
1435	movsl	%d0,%a0@+		| put lword
1436	nop				| sync
1437	movl	%a1@+,%d0		| get lword
1438	movsl	%d0,%a0@+		| put lword
1439	nop				| sync
1440	movl	%a1@+,%d0		| get lword
1441	movsl	%d0,%a0@+		| put lword
1442	nop				| sync
1443	movl	%a1@+,%d0		| get lword
1444	movsl	%d0,%a0@+		| put lword
1445	nop				| sync
1446	moveq	#0,%d0			| indicate no fault
1447	jra	Lsldone
1448Lslerr:
1449	moveq	#-1,%d0
1450Lsldone:
1451	movl	_C_LABEL(curpcb),%a1	| current pcb
1452	clrl	%a1@(PCB_ONFAULT) 	| clear fault address
1453	rts
1454#endif
1455
1456/*
1457 * Invalidate entire TLB.
1458 */
1459ENTRY(TBIA)
1460_C_LABEL(_TBIA):
1461#if defined(M68040)
1462	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1463	jne	Lmotommu3		| no, skip
1464	.word	0xf518			| yes, pflusha
1465	rts
1466Lmotommu3:
1467#endif
1468#if defined(M68K_MMU_MOTOROLA)
1469	tstl	_C_LABEL(mmutype)	| HP MMU?
1470	jeq	Lhpmmu6			| yes, skip
1471	pflusha				| flush entire TLB
1472	jpl	Lmc68851a		| 68851 implies no d-cache
1473	movl	#DC_CLEAR,%d0
1474	movc	%d0,%cacr		| invalidate on-chip d-cache
1475Lmc68851a:
1476	rts
1477Lhpmmu6:
1478#endif
1479#if defined(M68K_MMU_HP)
1480	MMUADDR(%a0)
1481	movl	%a0@(MMUTBINVAL),%sp@-	| do not ask me, this
1482	addql	#4,%sp			|   is how hpux does it
1483#ifdef DEBUG
1484	tstl	_ASM_LABEL(fullcflush)
1485	jne	_C_LABEL(_DCIA)		| XXX: invalidate entire cache
1486#endif
1487#endif
1488	rts
1489
1490/*
1491 * Invalidate any TLB entry for given VA (TB Invalidate Single)
1492 */
1493ENTRY(TBIS)
1494#ifdef DEBUG
1495	tstl	_ASM_LABEL(fulltflush)	| being conservative?
1496	jne	_C_LABEL(_TBIA)		| yes, flush entire TLB
1497#endif
1498#if defined(M68040)
1499	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1500	jne	Lmotommu4		| no, skip
1501	movl	%sp@(4),%a0
1502	movc	%dfc,%d1
1503	moveq	#1,%d0			| user space
1504	movc	%d0,%dfc
1505	.word	0xf508			| pflush %a0@
1506	moveq	#5,%d0			| super space
1507	movc	%d0,%dfc
1508	.word	0xf508			| pflush %a0@
1509	movc	%d1,%dfc
1510	rts
1511Lmotommu4:
1512#endif
1513#if defined(M68K_MMU_MOTOROLA)
1514	tstl	_C_LABEL(mmutype)	| HP MMU?
1515	jeq	Lhpmmu5			| yes, skip
1516	movl	%sp@(4),%a0		| get addr to flush
1517	jpl	Lmc68851b		| is 68851?
1518	pflush	#0,#0,%a0@		| flush address from both sides
1519	movl	#DC_CLEAR,%d0
1520	movc	%d0,%cacr		| invalidate on-chip data cache
1521	rts
1522Lmc68851b:
1523	pflushs	#0,#0,%a0@		| flush address from both sides
1524	rts
1525Lhpmmu5:
1526#endif
1527#if defined(M68K_MMU_HP)
1528	movl	%sp@(4),%d0		| VA to invalidate
1529	bclr	#0,%d0			| ensure even
1530	movl	%d0,%a0
1531	movw	%sr,%d1			| go critical
1532	movw	#PSL_HIGHIPL,%sr	|   while in purge space
1533	moveq	#FC_PURGE,%d0		| change address space
1534	movc	%d0,%dfc		|   for destination
1535	moveq	#0,%d0			| zero to invalidate?
1536	movsl	%d0,%a0@		| hit it
1537	moveq	#FC_USERD,%d0		| back to old
1538	movc	%d0,%dfc		|   address space
1539	movw	%d1,%sr			| restore IPL
1540#endif
1541	rts
1542
1543/*
1544 * Invalidate supervisor side of TLB
1545 */
1546ENTRY(TBIAS)
1547#ifdef DEBUG
1548	tstl	_ASM_LABEL(fulltflush)	| being conservative?
1549	jne	_C_LABEL(_TBIA)		| yes, flush everything
1550#endif
1551#if defined(M68040)
1552	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1553	jne	Lmotommu5		| no, skip
1554	.word	0xf518			| yes, pflusha (for now) XXX
1555	rts
1556Lmotommu5:
1557#endif
1558#if defined(M68K_MMU_MOTOROLA)
1559	tstl	_C_LABEL(mmutype)	| HP MMU?
1560	jeq	Lhpmmu7			| yes, skip
1561	jpl	Lmc68851c		| 68851?
1562	pflush #4,#4			| flush supervisor TLB entries
1563	movl	#DC_CLEAR,%d0
1564	movc	%d0,%cacr		| invalidate on-chip d-cache
1565	rts
1566Lmc68851c:
1567	pflushs #4,#4			| flush supervisor TLB entries
1568	rts
1569Lhpmmu7:
1570#endif
1571#if defined(M68K_MMU_HP)
1572	MMUADDR(%a0)
1573	movl	#0x8000,%d0		| more
1574	movl	%d0,%a0@(MMUTBINVAL)	|   HP magic
1575#ifdef DEBUG
1576	tstl	_ASM_LABEL(fullcflush)
1577	jne	_C_LABEL(_DCIS)		| XXX: invalidate entire sup. cache
1578#endif
1579#endif
1580	rts
1581
1582/*
1583 * Invalidate user side of TLB
1584 */
1585ENTRY(TBIAU)
1586#ifdef DEBUG
1587	tstl	_ASM_LABEL(fulltflush)	| being conservative?
1588	jne	_C_LABEL(_TBIA)		| yes, flush everything
1589#endif
1590#if defined(M68040)
1591	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1592	jne	Lmotommu6		| no, skip
1593	.word	0xf518			| yes, pflusha (for now) XXX
1594	rts
1595Lmotommu6:
1596#endif
1597#if defined(M68K_MMU_MOTOROLA)
1598	tstl	_C_LABEL(mmutype)	| HP MMU?
1599	jeq	Lhpmmu8			| yes, skip
1600	jpl	Lmc68851d		| 68851?
1601	pflush	#0,#4			| flush user TLB entries
1602	movl	#DC_CLEAR,%d0
1603	movc	%d0,%cacr		| invalidate on-chip d-cache
1604	rts
1605Lmc68851d:
1606	pflushs	#0,#4			| flush user TLB entries
1607	rts
1608Lhpmmu8:
1609#endif
1610#if defined(M68K_MMU_HP)
1611	MMUADDR(%a0)
1612	moveq	#0,%d0			| more
1613	movl	%d0,%a0@(MMUTBINVAL)	|   HP magic
1614#ifdef DEBUG
1615	tstl	_ASM_LABEL(fullcflush)
1616	jne	_C_LABEL(_DCIU)		| XXX: invalidate entire user cache
1617#endif
1618#endif
1619	rts
1620
1621/*
1622 * Invalidate instruction cache
1623 */
1624ENTRY(ICIA)
1625#if defined(M68040)
1626ENTRY(ICPA)
1627	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040
1628	jne	Lmotommu7		| no, skip
1629	.word	0xf498			| cinva ic
1630	rts
1631Lmotommu7:
1632#endif
1633	movl	#IC_CLEAR,%d0
1634	movc	%d0,%cacr		| invalidate i-cache
1635	rts
1636
1637/*
1638 * Invalidate data cache.
1639 * HP external cache allows for invalidation of user/supervisor portions.
1640 * NOTE: we do not flush 68030 on-chip cache as there are no aliasing
1641 * problems with DC_WA.  The only cases we have to worry about are context
1642 * switch and TLB changes, both of which are handled "in-line" in resume
1643 * and TBI*.
1644 */
1645ENTRY(DCIA)
1646_C_LABEL(_DCIA):
1647#if defined(M68040)
1648	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040
1649	jne	Lmotommu8		| no, skip
1650	/* XXX implement */
1651	rts
1652Lmotommu8:
1653#endif
1654#if defined(M68K_MMU_HP)
1655	tstl	_C_LABEL(ectype)	| got external VAC?
1656	jle	Lnocache2		| no, all done
1657	MMUADDR(%a0)
1658	andl	#~MMU_CEN,%a0@(MMUCMD)	| disable cache in MMU control reg
1659	orl	#MMU_CEN,%a0@(MMUCMD)	| reenable cache in MMU control reg
1660Lnocache2:
1661#endif
1662	rts
1663
1664ENTRY(DCIS)
1665_C_LABEL(_DCIS):
1666#if defined(M68040)
1667	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040
1668	jne	Lmotommu9		| no, skip
1669	/* XXX implement */
1670	rts
1671Lmotommu9:
1672#endif
1673#if defined(M68K_MMU_HP)
1674	tstl	_C_LABEL(ectype)	| got external VAC?
1675	jle	Lnocache3		| no, all done
1676	MMUADDR(%a0)
1677	movl	%a0@(MMUSSTP),%d0	| read the supervisor STP
1678	movl	%d0,%a0@(MMUSSTP)	| write it back
1679Lnocache3:
1680#endif
1681	rts
1682
1683ENTRY(DCIU)
1684_C_LABEL(_DCIU):
1685#if defined(M68040)
1686	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040
1687	jne	LmotommuA		| no, skip
1688	/* XXX implement */
1689	rts
1690LmotommuA:
1691#endif
1692#if defined(M68K_MMU_HP)
1693	tstl	_C_LABEL(ectype)	| got external VAC?
1694	jle	Lnocache4		| no, all done
1695	MMUADDR(%a0)
1696	movl	%a0@(MMUUSTP),%d0	| read the user STP
1697	movl	%d0,%a0@(MMUUSTP)	| write it back
1698Lnocache4:
1699#endif
1700	rts
1701
1702#if defined(M68040)
1703ENTRY(ICPL)
1704	movl	%sp@(4),%a0		| address
1705	.word	0xf488			| cinvl ic,%a0@
1706	rts
1707ENTRY(ICPP)
1708	movl	%sp@(4),%a0		| address
1709	.word	0xf490			| cinvp ic,%a0@
1710	rts
1711ENTRY(DCPL)
1712	movl	%sp@(4),%a0		| address
1713	.word	0xf448			| cinvl dc,%a0@
1714	rts
1715ENTRY(DCPP)
1716	movl	%sp@(4),%a0		| address
1717	.word	0xf450			| cinvp dc,%a0@
1718	rts
1719ENTRY(DCPA)
1720	.word	0xf458			| cinva dc
1721	rts
1722ENTRY(DCFL)
1723	movl	%sp@(4),%a0		| address
1724	.word	0xf468			| cpushl dc,%a0@
1725	rts
1726ENTRY(DCFP)
1727	movl	%sp@(4),%a0		| address
1728	.word	0xf470			| cpushp dc,%a0@
1729	rts
1730#endif
1731
1732ENTRY(PCIA)
1733#if defined(M68040)
1734ENTRY(DCFA)
1735	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040
1736	jne	LmotommuB		| no, skip
1737	.word	0xf478			| cpusha dc
1738	rts
1739LmotommuB:
1740#endif
1741#if defined(M68K_MMU_MOTOROLA)
1742	movl	#DC_CLEAR,%d0
1743	movc	%d0,%cacr		| invalidate on-chip d-cache
1744	tstl	_C_LABEL(ectype)	| got external PAC?
1745	jge	Lnocache6		| no, all done
1746	MMUADDR(%a0)
1747	andl	#~MMU_CEN,%a0@(MMUCMD)	| disable cache in MMU control reg
1748	orl	#MMU_CEN,%a0@(MMUCMD)	| reenable cache in MMU control reg
1749Lnocache6:
1750#endif
1751	rts
1752
1753ENTRY(ecacheon)
1754	tstl	_C_LABEL(ectype)
1755	jeq	Lnocache7
1756	MMUADDR(%a0)
1757	orl	#MMU_CEN,%a0@(MMUCMD)
1758Lnocache7:
1759	rts
1760
1761ENTRY(ecacheoff)
1762	tstl	_C_LABEL(ectype)
1763	jeq	Lnocache8
1764	MMUADDR(%a0)
1765	andl	#~MMU_CEN,%a0@(MMUCMD)
1766Lnocache8:
1767	rts
1768
1769ENTRY_NOPROFILE(getsfc)
1770	movc	%sfc,%d0
1771	rts
1772
1773ENTRY_NOPROFILE(getdfc)
1774	movc	%dfc,%d0
1775	rts
1776
1777/*
1778 * Load a new user segment table pointer.
1779 */
1780ENTRY(loadustp)
1781#if defined(M68K_MMU_MOTOROLA)
1782	tstl	_C_LABEL(mmutype)	| HP MMU?
1783	jeq	Lhpmmu9			| yes, skip
1784	movl	%sp@(4),%d0		| new USTP
1785	moveq	#PGSHIFT,%d1
1786	lsll	%d1,%d0			| convert to addr
1787#if defined(M68040)
1788	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1789	jne	LmotommuC		| no, skip
1790	.word	0xf518			| yes, pflusha
1791	.long	0x4e7b0806		| movc %d0,%urp
1792	rts
1793LmotommuC:
1794#endif
1795	pflusha				| flush entire TLB
1796	lea	_C_LABEL(protorp),%a0	| CRP prototype
1797	movl	%d0,%a0@(4)		| stash USTP
1798	pmove	%a0@,%crp		| load root pointer
1799	movl	#CACHE_CLR,%d0
1800	movc	%d0,%cacr		| invalidate cache(s)
1801	rts
1802Lhpmmu9:
1803#endif
1804#if defined(M68K_MMU_HP)
1805	movl	#CACHE_CLR,%d0
1806	movc	%d0,%cacr		| invalidate cache(s)
1807	MMUADDR(%a0)
1808	movl	%a0@(MMUTBINVAL),%d1	| invalidate TLB
1809	tstl	_C_LABEL(ectype)	| have external VAC?
1810	jle	1f			| no, skip
1811	andl	#~MMU_CEN,%a0@(MMUCMD)	| toggle cache enable
1812	orl	#MMU_CEN,%a0@(MMUCMD)	| to clear data cache
18131:
1814	movl	%sp@(4),%a0@(MMUUSTP)	| load a new USTP
1815#endif
1816	rts
1817
1818ENTRY(ploadw)
1819#if defined(M68K_MMU_MOTOROLA)
1820	movl	%sp@(4),%a0		| address to load
1821#if defined(M68K_MMU_HP)
1822	tstl	_C_LABEL(mmutype)	| HP MMU?
1823	jeq	Lploadwskp		| yes, skip
1824#endif
1825#if defined(M68040)
1826	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1827	jeq	Lploadwskp		| yes, skip
1828#endif
1829	ploadw	#1,%a0@			| pre-load translation
1830Lploadwskp:
1831#endif
1832	rts
1833
1834/*
1835 * Set processor priority level calls.  Most are implemented with
1836 * inline asm expansions.  However, spl0 requires special handling
1837 * as we need to check for our emulated software interrupts.
1838 */
1839
1840ENTRY(spl0)
1841	moveq	#0,%d0
1842	movw	%sr,%d0			| get old SR for return
1843	movw	#PSL_LOWIPL,%sr		| restore new SR
1844	tstb	_C_LABEL(ssir)		| software interrupt pending?
1845	jeq	Lspldone		| no, all done
1846	subql	#4,%sp			| make room for RTE frame
1847	movl	%sp@(4),%sp@(2)		| position return address
1848	clrw	%sp@(6)			| set frame type 0
1849	movw	#PSL_LOWIPL,%sp@	| and new SR
1850	jra	Lgotsir			| go handle it
1851Lspldone:
1852	rts
1853
1854/*
1855 * _delay(u_int N)
1856 *
1857 * Delay for at least (N/256) microsecends.
1858 * This routine depends on the variable:  delay_divisor
1859 * which should be set based on the CPU clock rate.
1860 */
1861ENTRY_NOPROFILE(_delay)
1862	| %d0 = arg = (usecs << 8)
1863	movl	%sp@(4),%d0
1864	| %d1 = delay_divisor
1865	movl	_C_LABEL(delay_divisor),%d1
1866	jra	L_delay			/* Jump into the loop! */
1867
1868	/*
1869	 * Align the branch target of the loop to a half-line (8-byte)
1870	 * boundary to minimize cache effects.  This guarantees both
1871	 * that there will be no prefetch stalls due to cache line burst
1872	 * operations and that the loop will run from a single cache
1873	 * half-line.
1874	 */
1875#ifdef __ELF__
1876	.align	8
1877#else
1878	.align	3
1879#endif
1880L_delay:
1881	subl	%d1,%d0
1882	jgt	L_delay
1883	rts
1884
1885/*
1886 * Save and restore 68881 state.
1887 */
1888ENTRY(m68881_save)
1889	movl	%sp@(4),%a0		| save area pointer
1890	fsave	%a0@			| save state
1891	tstb	%a0@			| null state frame?
1892	jeq	Lm68881sdone		| yes, all done
1893	fmovem	%fp0-%fp7,%a0@(FPF_REGS) | save FP general registers
1894	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR)	| save FP control registers
1895Lm68881sdone:
1896	rts
1897
1898ENTRY(m68881_restore)
1899	movl	%sp@(4),%a0		| save area pointer
1900	tstb	%a0@			| null state frame?
1901	jeq	Lm68881rdone		| yes, easy
1902	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi	| restore FP control registers
1903	fmovem	%a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers
1904Lm68881rdone:
1905	frestore %a0@			| restore state
1906	rts
1907
1908/*
1909 * Handle the nitty-gritty of rebooting the machine.
1910 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
1911 * Note that we must be running in an address range that is mapped one-to-one
1912 * logical to physical so that the PC is still valid immediately after the MMU
1913 * is turned off.  We have conveniently mapped the last page of physical
1914 * memory this way.
1915 */
1916ENTRY_NOPROFILE(doboot)
1917#if defined(M68040)
1918	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1919	jeq	Lnocache5		| yes, skip
1920#endif
1921	movl	#CACHE_OFF,%d0
1922	movc	%d0,%cacr		| disable on-chip cache(s)
1923	tstl	_C_LABEL(ectype)	| external cache?
1924	jeq	Lnocache5		| no, skip
1925	MMUADDR(%a0)
1926	andl	#~MMU_CEN,%a0@(MMUCMD)	| disable external cache
1927Lnocache5:
1928	lea	MAXADDR,%a0		| last page of physical memory
1929	movl	_C_LABEL(boothowto),%a0@+ | store howto
1930	movl	_C_LABEL(bootdev),%a0@+	| and devtype
1931	lea	Lbootcode,%a1		| start of boot code
1932	lea	Lebootcode,%a3		| end of boot code
1933Lbootcopy:
1934	movw	%a1@+,%a0@+		| copy a word
1935	cmpl	%a3,%a1			| done yet?
1936	jcs	Lbootcopy		| no, keep going
1937#if defined(M68040)
1938	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1939	jne	LmotommuE		| no, skip
1940	.word	0xf4f8			| cpusha bc
1941LmotommuE:
1942#endif
1943	jmp	MAXADDR+8		| jump to last page
1944
1945Lbootcode:
1946	lea	MAXADDR+0x800,%sp	| physical SP in case of NMI
1947#if defined(M68040)
1948	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1949	jne	LmotommuF		| no, skip
1950	movl	#0,%d0
1951	movc	%d0,%cacr		| caches off
1952	.long	0x4e7b0003		| movc %d0,%tc
1953	movl	%d2,MAXADDR+NBPG-4	| restore old high page contents
1954	DOREBOOT
1955LmotommuF:
1956#endif
1957#if defined(M68K_MMU_MOTOROLA)
1958	tstl	_C_LABEL(mmutype)	| HP MMU?
1959	jeq	LhpmmuB			| yes, skip
1960	movl	#0,%a0@			| value for pmove to TC (turn off MMU)
1961	pmove	%a0@,%tc		| disable MMU
1962	DOREBOOT
1963LhpmmuB:
1964#endif
1965#if defined(M68K_MMU_HP)
1966	MMUADDR(%a0)
1967	movl	#0xFFFF0000,%a0@(MMUCMD)	| totally disable MMU
1968	movl	%d2,MAXADDR+NBPG-4	| restore old high page contents
1969	DOREBOOT
1970#endif
1971Lebootcode:
1972
1973/*
1974 * Misc. global variables.
1975 */
1976	.data
1977GLOBAL(machineid)
1978	.long	HP_320			| default to 320
1979
1980GLOBAL(mmuid)
1981	.long	0			| default to nothing
1982
1983GLOBAL(mmutype)
1984	.long	MMU_HP			| default to HP MMU
1985
1986GLOBAL(cputype)
1987	.long	CPU_68020		| default to 68020 CPU
1988
1989GLOBAL(ectype)
1990	.long	EC_NONE			| external cache type, default to none
1991
1992GLOBAL(fputype)
1993	.long	FPU_68882		| default to 68882 FPU
1994
1995GLOBAL(protorp)
1996	.long	0,0			| prototype root pointer
1997
1998GLOBAL(prototc)
1999	.long	0			| prototype translation control
2000
2001GLOBAL(internalhpib)
2002	.long	1			| has internal HP-IB, default to yes
2003
2004GLOBAL(want_resched)
2005	.long	0
2006
2007GLOBAL(proc0paddr)
2008	.long	0			| KVA of proc0 u-area
2009
2010GLOBAL(intiobase)
2011	.long	0			| KVA of base of internal IO space
2012
2013GLOBAL(intiolimit)
2014	.long	0			| KVA of end of internal IO space
2015
2016GLOBAL(extiobase)
2017	.long	0			| KVA of base of external IO space
2018
2019GLOBAL(CLKbase)
2020	.long	0			| KVA of base of clock registers
2021
2022GLOBAL(MMUbase)
2023	.long	0			| KVA of base of HP MMU registers
2024
2025#ifdef USELEDS
2026ASLOCAL(heartbeat)
2027	.long	0			| clock ticks since last heartbeat
2028
2029ASLOCAL(beatstatus)
2030	.long	0			| for determining a fast or slow throb
2031#endif
2032
2033#ifdef DEBUG
2034ASGLOBAL(fulltflush)
2035	.long	0
2036
2037ASGLOBAL(fullcflush)
2038	.long	0
2039#endif
2040
2041/*
2042 * Interrupt Counters
2043 *
2044 * We now use the evcnt(9) subsystem, but these are provided to keep
2045 * vmstat(8) happy.
2046 */
2047
2048GLOBAL(intrnames)
2049GLOBAL(eintrnames)
2050GLOBAL(intrcnt)
2051GLOBAL(eintrcnt)
2052	.long 0
2053