xref: /netbsd/sys/arch/cesfic/cesfic/locore.s (revision c4a72b64)
1/*	$NetBSD: locore.s,v 1.6 2002/11/02 20:03:05 chs 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
52#include "assym.h"
53#include <machine/asm.h>
54#include <machine/trap.h>
55
56/*
57 * This is for kvm_mkdb, and should be the address of the beginning
58 * of the kernel text segment (not necessarily the same as kernbase).
59 */
60	.text
61GLOBAL(kernel_text)
62
63/*
64 * Temporary stack for a variety of purposes.
65 * Try and make this the first thing is the data segment so it
66 * is page aligned.  Note that if we overflow here, we run into
67 * our text segment.
68 */
69	.data
70	.space	NBPG
71ASLOCAL(tmpstk)
72
73#include <cesfic/cesfic/vectors.s>
74
75	.text
76
77/*
78 * Macro to relocate a symbol, used before MMU is enabled.
79 */
80#define	_RELOC(var, ar)		\
81	lea	var-KERNBASE,ar;		\
82	addl	%a5,ar
83
84#define	RELOC(var, ar)		_RELOC(_C_LABEL(var), ar)
85#define	ASRELOC(var, ar)	_RELOC(_ASM_LABEL(var), ar)
86
87/*
88 * Initialization
89 *
90 * A4 contains the address of the end of the symtab
91 * A5 contains physical load point from boot
92 * VBR contains zero from ROM.  Exceptions will continue to vector
93 * through ROM until MMU is turned on at which time they will vector
94 * through our table (vectors.s).
95 */
96
97BSS(lowram,4)
98BSS(esym,4)
99
100	.text
101ASENTRY_NOPROFILE(start)
102	movw	#PSL_HIGHIPL, %sr	| no interrupts
103	movl	#CACHE_OFF, %d0
104	movc	%d0, %cacr		| clear and disable on-chip cache(s)
105
106	/* XXX fixed load address */
107	movl	#0x20100000, %a5
108
109	movl	#0x20000000, %a0
110	RELOC(edata, %a1)
1111:
112	movl	%a5@+, %a0@+
113	cmpl	%a5, %a1
114	bne	1b
115
116	movl	#0x20000000, %a5
117
118	ASRELOC(tmpstk, %a0)
119	movl	%a0, %sp		| give ourselves a temporary stack
120
121	RELOC(edata, %a0)
122	RELOC(end, %a1)
1232:
124	clrb	%a0@+
125	cmpl	%a0, %a1
126	bne	2b
127
128	RELOC(esym, %a0)
129#if 0
130	movl	%a4, %a0@		| store end of symbol table
131#else
132	clrl	%a0@			| no symbol table, yet
133#endif
134
135	RELOC(lowram, %a0)
136	movl	%a5, %a0@		| store start of physical memory
137
138#if 0
139	RELOC(boothowto, %a0)		| save reboot flags
140	movl	%d7, %a0@
141	RELOC(bootdev, %a0)		|   and boot device
142	movl	%d6, %a0@
143#endif
144
145	/*
146	 * All data registers are now free.  All address registers
147	 * except a5 are free.  a5 is used by the RELOC() macro,
148	 * and cannot be used until after the MMU is enabled.
149	 */
150
151/* determine our CPU/MMU combo - check for all regardless of kernel config */
152	movl	#0x200,%d0		| data freeze bit
153	movc	%d0,%cacr		|   only exists on 68030
154	movc	%cacr,%d0		| read it back
155	tstl	%d0			| zero?
156	jeq	Lnot68030		| yes, we have 68020/68040
157	RELOC(mmutype, %a0)		| no, we have 68030
158	movl	#MMU_68030,%a0@		| set to reflect 68030 PMMU
159	RELOC(cputype, %a0)
160	movl	#CPU_68030,%a0@		| and 68030 CPU
161	jra	Lstart1
162Lnot68030:
163	bset	#31,%d0			| data cache enable bit
164	movc	%d0,%cacr		|   only exists on 68040
165	movc	%cacr,%d0		| read it back
166	tstl	%d0			| zero?
167	beq	Lis68020		| yes, we have 68020
168	moveq	#0,%d0			| now turn it back off
169	movec	%d0,%cacr		|   before we access any data
170	RELOC(mmutype, %a0)
171	movl	#MMU_68040,%a0@		| with a 68040 MMU
172	RELOC(cputype, %a0)
173	movl	#CPU_68040,%a0@		| and a 68040 CPU
174	RELOC(fputype, %a0)
175	movl	#FPU_68040,%a0@		| ...and FPU
176	jra	Lstart1
177Lis68020:
178	/* impossible */
179
180Lstart1:
181
182/* initialize source/destination control registers for movs */
183	moveq	#FC_USERD,%d0		| user space
184	movc	%d0,%sfc		|   as source
185	movc	%d0,%dfc		|   and destination of transfers
186
187/* initialize memory size (for pmap_bootstrap) */
188	movl	0x5c00ac00, %d0
189	andb	#0x60, %d0
190	jne	Lnot8M
191	movl	#0x20800000, %d1	| memory end, 8M
192	jra	Lmemok
193Lnot8M:
194	cmpb	#0x20, %d0
195	jne	Lunkmem
196	movl	#0x22000000, %d1	| memory end, 32M
197	jra	Lmemok
198Lunkmem:
199	/* ??? */
200	movl	#0x20400000, %d1	| memory end, assume at least 4M
201
202Lmemok:
203	moveq	#PGSHIFT,%d2
204	lsrl	%d2,%d1			| convert to page (click) number
205	movl	%a5,%d0			| lowram value from ROM via boot
206	lsrl	%d2,%d0			| convert to page number
207	subl	%d0,%d1			| compute amount of RAM present
208	RELOC(physmem, %a0)
209	movl	%d1,%a0@		| and physmem
210/* configure kernel and proc0 VA space so we can get going */
211	.globl	_Sysseg, _pmap_bootstrap, _avail_start
212#ifdef DDB
213	RELOC(esym,%a0)			| end of static kernel test/data/syms
214	movl	%a0@,%d5
215	jne	Lstart2
216#endif
217	movl	#_C_LABEL(end),%d5	| end of static kernel text/data
218Lstart2:
219	addl	#NBPG-1,%d5
220	andl	#PG_FRAME,%d5		| round to a page
221	movl	%d5,%a4
222	addl	%a5,%a4			| convert to PA
223	subl	#KERNBASE, %a4
224	pea	%a5@			| firstpa
225	pea	%a4@			| nextpa
226	RELOC(pmap_bootstrap,%a0)
227	jbsr	%a0@			| pmap_bootstrap(firstpa, nextpa)
228	addql	#8,%sp
229
230/*
231 * Prepare to enable MMU.
232 */
233	RELOC(Sysseg, %a0)		| system segment table addr
234	movl	%a0@,%d1		| read value (a KVA)
235	addl	%a5,%d1			| convert to PA
236	subl	#KERNBASE, %d1
237
238	RELOC(mmutype, %a0)
239	cmpl	#MMU_68040,%a0@		| 68040?
240	jne	Lmotommu1		| no, skip
241	.long	0x4e7b1807		| movc d1,srp
242	jra	Lstploaddone
243Lmotommu1:
244	RELOC(protorp, %a0)
245	movl	#0x80000202,%a0@	| nolimit + share global + 4 byte PTEs
246	movl	%d1,%a0@(4)		| + segtable address
247	pmove	%a0@,%srp		| load the supervisor root pointer
248	movl	#0x80000002,%a0@	| reinit upper half for CRP loads
249Lstploaddone:
250
251	RELOC(mmutype, %a0)
252	cmpl	#MMU_68040,%a0@		| 68040?
253	jne	Lmotommu2		| no, skip
254
255	movel #0x2000c000, %d0		| double map RAM
256	.long	0x4e7b0004		| movc d0,itt0
257	.long	0x4e7b0006		| movc d0,dtt0
258	moveq	#0, %d0			| ensure TT regs are disabled
259	.long	0x4e7b0005		| movc d0,itt1
260	.long	0x4e7b0007		| movc d0,dtt1
261
262	.word	0xf4d8			| cinva bc
263	.word	0xf518			| pflusha
264
265	movl	#0x8000, %d0
266	.long	0x4e7b0003		| movc d0,tc
267	movl	#0x80008000, %d0
268	movc	%d0, %cacr		| turn on both caches
269
270	jmp	Lenab1:l		| avoid pc-relative
271Lmotommu2:
272	/* XXX do TT here */
273	RELOC(prototc, %a2)
274	movl	#0x82c0aa00,%a2@	| value to load TC with
275	pmove	%a2@,%tc		| load it
276	jmp	Lenab1
277
278/*
279 * Should be running mapped from this point on
280 */
281Lenab1:
282	.word	0xf4d8			| cinva bc
283	.word	0xf518			| pflusha
284	nop
285	nop
286	nop
287	nop
288	nop
289	movl	#_C_LABEL(vectab),%d0	| set Vector Base Register
290	movc	%d0,%vbr
291	moveq	#0,%d0			| ensure TT regs are disabled
292	.long	0x4e7b0004		| movc d0,itt0
293	.long	0x4e7b0005		| movc d0,itt1
294	.long	0x4e7b0006		| movc d0,dtt0
295	.long	0x4e7b0007		| movc d0,dtt1
296
297/* select the software page size now */
298	lea	_ASM_LABEL(tmpstk),%sp	| temporary stack
299	jbsr	_C_LABEL(uvm_setpagesize)  | select software page size
300/* set kernel stack, user SP, and initial pcb */
301	movl	_C_LABEL(proc0paddr),%a1   | get proc0 pcb addr
302	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
303	lea	_C_LABEL(proc0),%a2	| initialize proc0.p_addr so that
304	movl	%a1,%a2@(P_ADDR)	|   we don't deref NULL in trap()
305	movl	#USRSTACK-4,%a2
306	movl	%a2,%usp		| init user SP
307	movl	%a1,_C_LABEL(curpcb)	| proc0 is running
308
309	tstl	_C_LABEL(fputype)	| Have an FPU?
310	jeq	Lenab2			| No, skip.
311	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
312	movl	%a1,%sp@-
313	jbsr	_C_LABEL(m68881_restore)   | restore it (does not kill a1)
314	addql	#4,%sp
315Lenab2:
316
317/* flush TLB and turn on caches */
318	jbsr	_C_LABEL(_TBIA)		| invalidate TLB
319	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
320	jeq	Lnocache0		| yes, cache already on
321	movl	#CACHE_ON,%d0
322	movc	%d0,%cacr		| clear cache(s)
323Lnocache0:
324
325/* Final setup for call to main(). */
326	jbsr	_C_LABEL(fic_init)
327
328/*
329 * Create a fake exception frame so that cpu_fork() can copy it.
330 * main() nevers returns; we exit to user mode from a forked process
331 * later on.
332 */
333	clrw	%sp@-			| vector offset/frame type
334	clrl	%sp@-			| PC - filled in by "execve"
335	movw	#PSL_USER,%sp@-		| in user mode
336	clrl	%sp@-			| stack adjust count and padding
337	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
338	lea	_C_LABEL(proc0),%a0	| save pointer to frame
339	movl	%sp,%a0@(P_MD_REGS)	|   in proc0.p_md.md_regs
340
341	jra	_C_LABEL(main)		| main()
342
343	pea	Lmainreturned		| Yow!  Main returned!
344	jbsr	_C_LABEL(panic)
345	/* NOTREACHED */
346Lmainreturned:
347	.asciz	"main() returned"
348	.even
349
350GLOBAL(proc_trampoline)
351	movl	%a3,%sp@-
352	jbsr	%a2@
353	addql	#4,%sp
354	movl	%sp@(FR_SP),%a0		| grab and load
355	movl	%a0,%usp		|   user SP
356	moveml	%sp@+,#0x7FFF		| restore most user regs
357	addql	#8,%sp			| toss SP and stack adjust
358	jra	_ASM_LABEL(rei)		| and return
359
360
361/*
362 * Trap/interrupt vector routines
363 */
364#include <m68k/m68k/trap_subr.s>
365
366	.data
367GLOBAL(m68k_fault_addr)
368	.long	0
369
370#if defined(M68040) || defined(M68060)
371ENTRY_NOPROFILE(addrerr4060)
372	clrl	%sp@-			| stack adjust count
373	moveml	#0xFFFF,%sp@-		| save user registers
374	movl	%usp,%a0			| save the user SP
375	movl	%a0,%sp@(FR_SP)		|   in the savearea
376	movl	%sp@(FR_HW+8),%sp@-
377	clrl	%sp@-			| dummy code
378	movl	#T_ADDRERR,%sp@-		| mark address error
379	jra	_ASM_LABEL(faultstkadj)	| and deal with it
380#endif
381
382#if defined(M68060)
383	clrl	%sp@-			| stack adjust count
384	moveml	#0xFFFF,%sp@-		| save user registers
385	movl	%usp,%a0			| save the user SP
386	movl	%a0,%sp@(FR_SP)		|   in the savearea
387	movel	%sp@(FR_HW+12),%d0	| FSLW
388	btst	#2,%d0			| branch prediction error?
389	jeq	Lnobpe
390	movc	%cacr,%d2
391	orl	#IC60_CABC,%d2		| clear all branch cache entries
392	movc	%d2,%cacr
393	movl	%d0,%d1
394	addql	#1,L60bpe
395	andl	#0x7ffd,%d1
396	jeq	_ASM_LABEL(faultstkadjnotrap2)
397Lnobpe:
398| we need to adjust for misaligned addresses
399	movl	%sp@(FR_HW+8),%d1		| grab VA
400	btst	#27,%d0			| check for mis-aligned access
401	jeq	Lberr3			| no, skip
402	addl	#28,%d1			| yes, get into next page
403					| operand case: 3,
404					| instruction case: 4+12+12
405	andl	#PG_FRAME,%d1            | and truncate
406Lberr3:
407	movl	%d1,%sp@-
408	movl	%d0,%sp@-			| code is FSLW now.
409	andw	#0x1f80,%d0
410	jeq	Lberr60			| it is a bus error
411	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
412	jra	_ASM_LABEL(faultstkadj)	| and deal with it
413Lberr60:
414	tstl	_C_LABEL(nofault)	| catch bus error?
415	jeq	Lisberr			| no, handle as usual
416	movl	%sp@(FR_HW+8+8),_C_LABEL(m68k_fault_addr) | save fault addr
417	movl	_C_LABEL(nofault),%sp@-	| yes,
418	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
419	/* NOTREACHED */
420#endif
421#if defined(M68040)
422ENTRY_NOPROFILE(buserr40)
423	clrl	%sp@-			| stack adjust count
424	moveml	#0xFFFF,%sp@-		| save user registers
425	movl	%usp,%a0			| save the user SP
426	movl	%a0,%sp@(FR_SP)		|   in the savearea
427	movl	%sp@(FR_HW+20),%d1	| get fault address
428	moveq	#0,%d0
429	movw	%sp@(FR_HW+12),%d0	| get SSW
430	btst	#11,%d0			| check for mis-aligned
431	jeq	Lbe1stpg		| no skip
432	addl	#3,%d1			| get into next page
433	andl	#PG_FRAME,%d1		| and truncate
434Lbe1stpg:
435	movl	%d1,%sp@-			| pass fault address.
436	movl	%d0,%sp@-			| pass SSW as code
437	btst	#10,%d0			| test ATC
438	jeq	Lberr40			| it is a bus error
439	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
440	jra	_ASM_LABEL(faultstkadj)	| and deal with it
441Lberr40:
442	tstl	_C_LABEL(nofault)	| catch bus error?
443	jeq	Lisberr			| no, handle as usual
444	movl	%sp@(FR_HW+8+20),_C_LABEL(m68k_fault_addr) | save fault addr
445	movl	_C_LABEL(nofault),%sp@-	| yes,
446	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
447	/* NOTREACHED */
448#endif
449
450#if defined(M68020) || defined(M68030)
451ENTRY_NOPROFILE(busaddrerr2030)
452	clrl	%sp@-			| stack adjust count
453	moveml	#0xFFFF,%sp@-		| save user registers
454	movl	%usp,%a0			| save the user SP
455	movl	%a0,%sp@(FR_SP)		|   in the savearea
456	moveq	#0,%d0
457	movw	%sp@(FR_HW+10),%d0	| grab SSW for fault processing
458	btst	#12,%d0			| RB set?
459	jeq	LbeX0			| no, test RC
460	bset	#14,%d0			| yes, must set FB
461	movw	%d0,%sp@(FR_HW+10)	| for hardware too
462LbeX0:
463	btst	#13,%d0			| RC set?
464	jeq	LbeX1			| no, skip
465	bset	#15,%d0			| yes, must set FC
466	movw	%d0,%sp@(FR_HW+10)	| for hardware too
467LbeX1:
468	btst	#8,%d0			| data fault?
469	jeq	Lbe0			| no, check for hard cases
470	movl	%sp@(FR_HW+16),%d1	| fault address is as given in frame
471	jra	Lbe10			| thats it
472Lbe0:
473	btst	#4,%sp@(FR_HW+6)		| long (type B) stack frame?
474	jne	Lbe4			| yes, go handle
475	movl	%sp@(FR_HW+2),%d1		| no, can use save PC
476	btst	#14,%d0			| FB set?
477	jeq	Lbe3			| no, try FC
478	addql	#4,%d1			| yes, adjust address
479	jra	Lbe10			| done
480Lbe3:
481	btst	#15,%d0			| FC set?
482	jeq	Lbe10			| no, done
483	addql	#2,%d1			| yes, adjust address
484	jra	Lbe10			| done
485Lbe4:
486	movl	%sp@(FR_HW+36),%d1	| long format, use stage B address
487	btst	#15,%d0			| FC set?
488	jeq	Lbe10			| no, all done
489	subql	#2,%d1			| yes, adjust address
490Lbe10:
491	movl	%d1,%sp@-			| push fault VA
492	movl	%d0,%sp@-			| and padded SSW
493	movw	%sp@(FR_HW+8+6),%d0	| get frame format/vector offset
494	andw	#0x0FFF,%d0		| clear out frame format
495	cmpw	#12,%d0			| address error vector?
496	jeq	Lisaerr			| yes, go to it
497#if defined(M68K_MMU_MOTOROLA)
498#if defined(M68K_MMU_HP)
499	tstl	_C_LABEL(mmutype)	| HP MMU?
500	jeq	Lbehpmmu		| yes, different MMU fault handler
501#endif
502	movl	%d1,%a0			| fault address
503	movl	%sp@,%d0			| function code from ssw
504	btst	#8,%d0			| data fault?
505	jne	Lbe10a
506	movql	#1,%d0			| user program access FC
507					| (we dont separate data/program)
508	btst	#5,%sp@(FR_HW+8)		| supervisor mode?
509	jeq	Lbe10a			| if no, done
510	movql	#5,%d0			| else supervisor program access
511Lbe10a:
512	ptestr	%d0,%a0@,#7		| do a table search
513	pmove	%psr,%sp@			| save result
514	movb	%sp@,%d1
515	btst	#2,%d1			| invalid (incl. limit viol. and berr)?
516	jeq	Lmightnotbemerr		| no -> wp check
517	btst	#7,%d1			| is it MMU table berr?
518	jne	Lisberr1		| yes, needs not be fast.
519#endif /* M68K_MMU_MOTOROLA */
520Lismerr:
521	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
522	jra	_ASM_LABEL(faultstkadj)	| and deal with it
523#if defined(M68K_MMU_MOTOROLA)
524Lmightnotbemerr:
525	btst	#3,%d1			| write protect bit set?
526	jeq	Lisberr1		| no: must be bus error
527	movl	%sp@,%d0			| ssw into low word of %d0
528	andw	#0xc0,%d0		| Write protect is set on page:
529	cmpw	#0x40,%d0		| was it read cycle?
530	jne	Lismerr			| no, was not WPE, must be MMU fault
531	jra	Lisberr1		| real bus err needs not be fast.
532#endif /* M68K_MMU_MOTOROLA */
533#if defined(M68K_MMU_HP)
534Lbehpmmu:
535	MMUADDR(%a0)
536	movl	%a0@(MMUSTAT),%d0		| read MMU status
537	btst	#3,%d0			| MMU fault?
538	jeq	Lisberr1		| no, just a non-MMU bus error
539	andl	#~MMU_FAULT,%a0@(MMUSTAT)| yes, clear fault bits
540	movw	%d0,%sp@			| pass MMU stat in upper half of code
541	jra	Lismerr			| and handle it
542#endif
543Lisaerr:
544	movl	#T_ADDRERR,%sp@-		| mark address error
545	jra	_ASM_LABEL(faultstkadj)	| and deal with it
546Lisberr1:
547	clrw	%sp@			| re-clear pad word
548	tstl	_C_LABEL(nofault)	| catch bus error?
549	jeq	Lisberr			| no, handle as usual
550	movl	%sp@(FR_HW+8+16),_C_LABEL(m68k_fault_addr) | save fault addr
551	movl	_C_LABEL(nofault),%sp@-	| yes,
552	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
553	/* NOTREACHED */
554#endif /* M68020 || M68030 */
555
556Lisberr:				| also used by M68040/60
557	movl	#T_BUSERR,%sp@-		| mark bus error
558	jra	_ASM_LABEL(faultstkadj)	| and deal with it
559
560/*
561 * FP exceptions.
562 */
563ENTRY_NOPROFILE(fpfline)
564#if defined(M68040)
565	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
566	jne	Lfp_unimp		| no, skip FPSP
567	cmpw	#0x202c,%sp@(6)		| format type 2?
568	jne	_C_LABEL(illinst)	| no, not an FP emulation
569Ldofp_unimp:
570#ifdef FPSP
571#if 0
572	addl	#1, _C_LABEL(evcnt_fpsp_unimp)+EVCNT_COUNT
573#endif
574	jmp	_ASM_LABEL(fpsp_unimp)	| yes, go handle it
575#endif
576Lfp_unimp:
577#endif /* M68040 */
578#ifdef FPU_EMULATE
579	clrl	%sp@-			| stack adjust count
580	moveml	#0xFFFF,%sp@-		| save registers
581	moveq	#T_FPEMULI,%d0		| denote as FP emulation trap
582	jra	_ASM_LABEL(fault)	| do it
583#else
584	jra	_C_LABEL(illinst)
585#endif
586
587ENTRY_NOPROFILE(fpunsupp)
588#if defined(M68040)
589	cmpl	#FPU_68040,_C_LABEL(fputype) | 68040 FPU?
590	jne	_C_LABEL(illinst)	| no, treat as illinst
591#ifdef FPSP
592#if 0
593	addl	#1, _C_LABEL(evcnt_fpsp_unsupp)+EVCNT_COUNT
594#endif
595	jmp	_ASM_LABEL(fpsp_unsupp)	| yes, go handle it
596#endif
597Lfp_unsupp:
598#endif /* M68040 */
599#ifdef FPU_EMULATE
600	clrl	%sp@-			| stack adjust count
601	moveml	#0xFFFF,%sp@-		| save registers
602	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
603	jra	_ASM_LABEL(fault)	| do it
604#else
605	jra	_C_LABEL(illinst)
606#endif
607
608/*
609 * Handles all other FP coprocessor exceptions.
610 * Note that since some FP exceptions generate mid-instruction frames
611 * and may cause signal delivery, we need to test for stack adjustment
612 * after the trap call.
613 */
614ENTRY_NOPROFILE(fpfault)
615	clrl	%sp@-		| stack adjust count
616	moveml	#0xFFFF,%sp@-	| save user registers
617	movl	%usp,%a0		| and save
618	movl	%a0,%sp@(FR_SP)	|   the user stack pointer
619	clrl	%sp@-		| no VA arg
620	movl	_C_LABEL(curpcb),%a0 | current pcb
621	lea	%a0@(PCB_FPCTX),%a0 | address of FP savearea
622	fsave	%a0@		| save state
623#if defined(M68040) || defined(M68060)
624	/* always null state frame on 68040, 68060 */
625	cmpl	#FPU_68040,_C_LABEL(fputype)
626	jle	Lfptnull
627#endif
628	tstb	%a0@		| null state frame?
629	jeq	Lfptnull	| yes, safe
630	clrw	%d0		| no, need to tweak BIU
631	movb	%a0@(1),%d0	| get frame size
632	bset	#3,%a0@(0,%d0:w)	| set exc_pend bit of BIU
633Lfptnull:
634	fmovem	%fpsr,%sp@-	| push %fpsr as code argument
635	frestore %a0@		| restore state
636	movl	#T_FPERR,%sp@-	| push type arg
637	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
638
639
640ENTRY_NOPROFILE(badtrap)
641	moveml	#0xC0C0,%sp@-		| save scratch regs
642	movw	%sp@(22),%sp@-		| push exception vector info
643	clrw	%sp@-
644	movl	%sp@(22),%sp@-		| and PC
645	jbsr	_C_LABEL(straytrap)	| report
646	addql	#8,%sp			| pop args
647	moveml	%sp@+,#0x0303		| restore regs
648	jra	_ASM_LABEL(rei)		| all done
649
650ENTRY_NOPROFILE(trap0)
651	clrl	%sp@-			| stack adjust count
652	moveml	#0xFFFF,%sp@-		| save user registers
653	movl	%usp,%a0			| save the user SP
654	movl	%a0,%sp@(FR_SP)		|   in the savearea
655	movl	%d0,%sp@-			| push syscall number
656	jbsr	_C_LABEL(syscall)	| handle it
657	addql	#4,%sp			| pop syscall arg
658	tstl	_C_LABEL(astpending)
659	jne	Lrei2
660	tstb	_C_LABEL(ssir)
661	jeq	Ltrap1
662	movw	#SPL1,%sr
663	tstb	_C_LABEL(ssir)
664	jne	Lsir1
665Ltrap1:
666	movl	%sp@(FR_SP),%a0		| grab and restore
667	movl	%a0,%usp			|   user SP
668	moveml	%sp@+,#0x7FFF		| restore most registers
669	addql	#8,%sp			| pop SP and stack adjust
670	rte
671
672/*
673 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
674 *	cachectl(command, addr, length)
675 * command in d0, addr in a1, length in d1
676 */
677ENTRY_NOPROFILE(trap12)
678	movl	_C_LABEL(curproc),%sp@-	| push current proc pointer
679	movl	%d1,%sp@-			| push length
680	movl	%a1,%sp@-			| push addr
681	movl	%d0,%sp@-			| push command
682	jbsr	_C_LABEL(cachectl1)	| do it
683	lea	%sp@(16),%sp		| pop args
684	jra	_ASM_LABEL(rei)		| all done
685
686/*
687 * Trace (single-step) trap.  Kernel-mode is special.
688 * User mode traps are simply passed on to trap().
689 */
690ENTRY_NOPROFILE(trace)
691	clrl	%sp@-			| stack adjust count
692	moveml	#0xFFFF,%sp@-
693	moveq	#T_TRACE,%d0
694
695	| Check PSW and see what happen.
696	|   T=0 S=0	(should not happen)
697	|   T=1 S=0	trace trap from user mode
698	|   T=0 S=1	trace trap on a trap instruction
699	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
700
701	movw	%sp@(FR_HW),%d1		| get PSW
702	notw	%d1			| XXX no support for T0 on 680[234]0
703	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
704	jeq	Lkbrkpt			| yes, kernel breakpoint
705	jra	_ASM_LABEL(fault)	| no, user-mode fault
706
707
708/*
709 * Trap 15 is used for:
710 *	- GDB breakpoints (in user programs)
711 *	- KGDB breakpoints (in the kernel)
712 *	- trace traps for SUN binaries (not fully supported yet)
713 * User mode traps are simply passed to trap().
714 */
715ENTRY_NOPROFILE(trap15)
716	clrl	%sp@-			| stack adjust count
717	moveml	#0xFFFF,%sp@-
718	moveq	#T_TRAP15,%d0
719	movw	%sp@(FR_HW),%d1		| get PSW
720	andw	#PSL_S,%d1		| from system mode?
721	jne	Lkbrkpt			| yes, kernel breakpoint
722	jra	_ASM_LABEL(fault)	| no, user-mode fault
723
724Lkbrkpt: | Kernel-mode breakpoint or trace trap. (%d0=trap_type)
725	| Save the system sp rather than the user sp.
726	movw	#PSL_HIGHIPL,%sr		| lock out interrupts
727	lea	%sp@(FR_SIZE),%a6		| Save stack pointer
728	movl	%a6,%sp@(FR_SP)		|  from before trap
729
730	| If were are not on tmpstk switch to it.
731	| (so debugger can change the stack pointer)
732	movl	%a6,%d1
733	cmpl	#_ASM_LABEL(tmpstk),%d1
734	jls	Lbrkpt2			| already on tmpstk
735	| Copy frame to the temporary stack
736	movl	%sp,%a0			| %a0=src
737	lea	_ASM_LABEL(tmpstk)-96,%a1 | a1=dst
738	movl	%a1,%sp			| %sp=new frame
739	moveq	#FR_SIZE,%d1
740Lbrkpt1:
741	movl	%a0@+,%a1@+
742	subql	#4,%d1
743	bgt	Lbrkpt1
744
745Lbrkpt2:
746	| Call the trap handler for the kernel debugger.
747	| Do not call trap() to do it, so that we can
748	| set breakpoints in trap() if we want.  We know
749	| the trap type is either T_TRACE or T_BREAKPOINT.
750	movl	%d0,%sp@-		| push trap type
751	jbsr	_C_LABEL(trap_kdebug)
752	addql	#4,%sp			| pop args
753
754	| The stack pointer may have been modified, or
755	| data below it modified (by kgdb push call),
756	| so push the hardware frame at the current sp
757	| before restoring registers and returning.
758
759	movl	%sp@(FR_SP),%a0		| modified %sp
760	lea	%sp@(FR_SIZE),%a1		| end of our frame
761	movl	%a1@-,%a0@-		| copy 2 longs with
762	movl	%a1@-,%a0@-		| ... predecrement
763	movl	%a0,%sp@(FR_SP)		| %sp = h/w frame
764	moveml	%sp@+,#0x7FFF		| restore all but %sp
765	movl	%sp@,%sp			| ... and %sp
766	rte				| all done
767
768/* Use common m68k sigreturn */
769#include <m68k/m68k/sigreturn.s>
770
771/*
772 * Interrupt handlers.
773 * All device interrupts are auto-vectored.  The CPU provides
774 * the vector 0x18+level.  Note we count spurious interrupts, but
775 * we don't do anything else with them.
776 */
777
778#define INTERRUPT_SAVEREG	moveml	#0xC0C0,%sp@-
779#define INTERRUPT_RESTOREREG	moveml	%sp@+,#0x0303
780
781ENTRY_NOPROFILE(spurintr)	/* level 0 */
782	addql	#1,_C_LABEL(intrcnt)+0
783	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
784	jra	_ASM_LABEL(rei)
785
786ENTRY_NOPROFILE(intrhand)	/* levels 1 through 5 */
787	INTERRUPT_SAVEREG
788	movw	%sp@(22),%sp@-		| push exception vector info
789	clrw	%sp@-
790	jbsr	_C_LABEL(isrdispatch)	| call dispatch routine
791	addql	#4,%sp
792	INTERRUPT_RESTOREREG
793	jra	_ASM_LABEL(rei)		| all done
794
795ENTRY_NOPROFILE(lev6intr)	/* Level 6: clock */
796	INTERRUPT_SAVEREG
797	/* XXX */
798	movl _C_LABEL(clockbase), %a0
799	movl %a0@, %d0
800	movl %d0, %a0@
801	btst #2, %d0
802	jeq 1f
803	addql	#1,_C_LABEL(intrcnt)+24
804	lea	%sp@(16), %a1		| a1 = &clockframe
805	movl	%a1, %sp@-
806	jbsr	_C_LABEL(hardclock)	| hardclock(&frame)
807	addql	#4, %sp
808	jra 2f
8091:
810	movl	%d0, %sp@-
811	jbsr	_C_LABEL(otherclock)
812	addql	#4, %sp
8132:
814	INTERRUPT_RESTOREREG
815	jra	_ASM_LABEL(rei)		| all done
816
817ENTRY_NOPROFILE(lev7intr)	/* level 7: parity errors, reset key */
818	addql	#1,_C_LABEL(intrcnt)+28
819	clrl	%sp@-
820	moveml	#0xFFFF,%sp@-		| save registers
821	movl	%usp,%a0			| and save
822	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
823	jbsr	_C_LABEL(nmihand)	| call handler
824	movl	%sp@(FR_SP),%a0		| restore
825	movl	%a0,%usp			|   user SP
826	moveml	%sp@+,#0x7FFF		| and remaining registers
827	addql	#8,%sp			| pop SP and stack adjust
828	jra	_ASM_LABEL(rei)		| all done
829
830/*
831 * Emulation of VAX REI instruction.
832 *
833 * This code deals with checking for and servicing ASTs
834 * (profiling, scheduling) and software interrupts (network, softclock).
835 * We check for ASTs first, just like the VAX.  To avoid excess overhead
836 * the T_ASTFLT handling code will also check for software interrupts so we
837 * do not have to do it here.  After identifing that we need an AST we
838 * drop the IPL to allow device interrupts.
839 *
840 * This code is complicated by the fact that sendsig may have been called
841 * necessitating a stack cleanup.
842 */
843BSS(ssir,1)
844
845ASENTRY_NOPROFILE(rei)
846	tstl	_C_LABEL(astpending)	| AST pending?
847	jeq	Lchksir			| no, go check for SIR
848Lrei1:
849	btst	#5,%sp@			| yes, are we returning to user mode?
850	jne	Lchksir			| no, go check for SIR
851	movw	#PSL_LOWIPL,%sr		| lower SPL
852	clrl	%sp@-			| stack adjust
853	moveml	#0xFFFF,%sp@-		| save all registers
854	movl	%usp,%a1			| including
855	movl	%a1,%sp@(FR_SP)		|    the users SP
856Lrei2:
857	clrl	%sp@-			| VA == none
858	clrl	%sp@-			| code == none
859	movl	#T_ASTFLT,%sp@-		| type == async system trap
860	jbsr	_C_LABEL(trap)		| go handle it
861	lea	%sp@(12),%sp		| pop value args
862	movl	%sp@(FR_SP),%a0		| restore user SP
863	movl	%a0,%usp			|   from save area
864	movw	%sp@(FR_ADJ),%d0		| need to adjust stack?
865	jne	Laststkadj		| yes, go to it
866	moveml	%sp@+,#0x7FFF		| no, restore most user regs
867	addql	#8,%sp			| toss SP and stack adjust
868	rte				| and do real RTE
869Laststkadj:
870	lea	%sp@(FR_HW),%a1		| pointer to HW frame
871	addql	#8,%a1			| source pointer
872	movl	%a1,%a0			| source
873	addw	%d0,%a0			|  + hole size = dest pointer
874	movl	%a1@-,%a0@-		| copy
875	movl	%a1@-,%a0@-		|  8 bytes
876	movl	%a0,%sp@(FR_SP)		| new SSP
877	moveml	%sp@+,#0x7FFF		| restore user registers
878	movl	%sp@,%sp			| and our SP
879	rte				| and do real RTE
880Lchksir:
881	tstb	_C_LABEL(ssir)		| SIR pending?
882	jeq	Ldorte			| no, all done
883	movl	%d0,%sp@-			| need a scratch register
884	movw	%sp@(4),%d0		| get SR
885	andw	#PSL_IPL7,%d0		| mask all but IPL
886	jne	Lnosir			| came from interrupt, no can do
887	movl	%sp@+,%d0			| restore scratch register
888Lgotsir:
889	movw	#SPL1,%sr		| prevent others from servicing int
890	tstb	_C_LABEL(ssir)		| too late?
891	jeq	Ldorte			| yes, oh well...
892	clrl	%sp@-			| stack adjust
893	moveml	#0xFFFF,%sp@-		| save all registers
894	movl	%usp,%a1			| including
895	movl	%a1,%sp@(FR_SP)		|    the users SP
896Lsir1:
897	clrl	%sp@-			| VA == none
898	clrl	%sp@-			| code == none
899	movl	#T_SSIR,%sp@-		| type == software interrupt
900	jbsr	_C_LABEL(trap)		| go handle it
901	lea	%sp@(12),%sp		| pop value args
902	movl	%sp@(FR_SP),%a0		| restore
903	movl	%a0,%usp			|   user SP
904	moveml	%sp@+,#0x7FFF		| and all remaining registers
905	addql	#8,%sp			| pop SP and stack adjust
906	rte
907Lnosir:
908	movl	%sp@+,%d0			| restore scratch register
909Ldorte:
910	rte				| real return
911
912/*
913 * Use common m68k sigcode.
914 */
915#include <m68k/m68k/sigcode.s>
916#ifdef COMPAT_SUNOS
917#include <m68k/m68k/sunos_sigcode.s>
918#endif
919#ifdef COMPAT_SVR4
920#include <m68k/m68k/svr4_sigcode.s>
921#endif
922
923/*
924 * Primitives
925 */
926
927/*
928 * Use common m68k support routines.
929 */
930#include <m68k/m68k/support.s>
931
932/*
933 * Use common m68k process manipulation routines.
934 */
935#include <m68k/m68k/proc_subr.s>
936
937	.data
938GLOBAL(curpcb)
939GLOBAL(masterpaddr)		| XXX compatibility (debuggers)
940	.long	0
941
942ASLOCAL(mdpflag)
943	.byte	0		| copy of proc md_flags low byte
944#ifdef __ELF__
945	.align	4
946#else
947	.align	2
948#endif
949
950ASBSS(nullpcb,SIZEOF_PCB)
951
952/*
953 * At exit of a process, do a switch for the last time.
954 * Switch to a safe stack and PCB, and deallocate the process's resources.
955 */
956ENTRY(switch_exit)
957	movl	%sp@(4),%a0
958	/* save state into garbage pcb */
959	movl	#_ASM_LABEL(nullpcb),_C_LABEL(curpcb)
960	lea	_ASM_LABEL(tmpstk),%sp	| goto a tmp stack
961
962	/* Schedule the vmspace and stack to be freed. */
963	movl	%a0,%sp@-			| exit2(p)
964	jbsr	_C_LABEL(exit2)
965	lea	%sp@(4),%sp		| pop args
966
967	jra	_C_LABEL(cpu_switch)
968
969/*
970 * When no processes are on the runq, Swtch branches to Idle
971 * to wait for something to come ready.
972 */
973ASENTRY_NOPROFILE(Idle)
974	stop	#PSL_LOWIPL
975	movw	#PSL_HIGHIPL,%sr
976	movl	_C_LABEL(sched_whichqs),%d0
977	jeq	_ASM_LABEL(Idle)
978	jra	Lsw1
979
980Lbadsw:
981	PANIC("switch")
982	/*NOTREACHED*/
983
984/*
985 * cpu_switch()
986 *
987 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
988 * entire ATC.  The effort involved in selective flushing may not be
989 * worth it, maybe we should just flush the whole thing?
990 *
991 * NOTE 2: With the new VM layout we now no longer know if an inactive
992 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
993 * bit).  For now, we just always flush the full ATC.
994 */
995ENTRY(cpu_switch)
996	movl	_C_LABEL(curpcb),%a0	| current pcb
997	movw	%sr,%a0@(PCB_PS)		| save %sr before changing ipl
998#ifdef notyet
999	movl	_C_LABEL(curproc),%sp@-	| remember last proc running
1000#endif
1001	clrl	_C_LABEL(curproc)
1002
1003	/*
1004	 * Find the highest-priority queue that isn't empty,
1005	 * then take the first proc from that queue.
1006	 */
1007	movw	#PSL_HIGHIPL,%sr		| lock out interrupts
1008	movl	_C_LABEL(sched_whichqs),%d0
1009	jeq	_ASM_LABEL(Idle)
1010Lsw1:
1011	movl	%d0,%d1
1012	negl	%d0
1013	andl	%d1,%d0
1014	bfffo	%d0{#0:#32},%d1
1015	eorib	#31,%d1
1016
1017	movl	%d1,%d0
1018	lslb	#3,%d1			| convert queue number to index
1019	addl	#_C_LABEL(sched_qs),%d1	| locate queue (q)
1020	movl	%d1,%a1
1021	movl	%a1@(P_FORW),%a0		| p = q->p_forw
1022	cmpal	%d1,%a0			| anyone on queue?
1023	jeq	Lbadsw			| no, panic
1024	movl	%a0@(P_FORW),%a1@(P_FORW)	| q->p_forw = p->p_forw
1025	movl	%a0@(P_FORW),%a1		| n = p->p_forw
1026	movl	%d1,%a1@(P_BACK)		| n->p_back = q
1027	cmpal	%d1,%a1			| anyone left on queue?
1028	jne	Lsw2			| yes, skip
1029	movl	_C_LABEL(sched_whichqs),%d1
1030	bclr	%d0,%d1			| no, clear bit
1031	movl	%d1,_C_LABEL(sched_whichqs)
1032Lsw2:
1033	/* p->p_cpu initialized in fork1() for single-processor */
1034	movb	#SONPROC,%a0@(P_STAT)	| p->p_stat = SONPROC
1035	movl	%a0,_C_LABEL(curproc)
1036	clrl	_C_LABEL(want_resched)
1037#ifdef notyet
1038	movl	%sp@+,%a1
1039	cmpl	%a0,%a1			| switching to same proc?
1040	jeq	Lswdone			| yes, skip save and restore
1041#endif
1042	/*
1043	 * Save state of previous process in its pcb.
1044	 */
1045	movl	_C_LABEL(curpcb),%a1
1046	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
1047	movl	%usp,%a2			| grab USP (%a2 has been saved)
1048	movl	%a2,%a1@(PCB_USP)		| and save it
1049
1050	tstl	_C_LABEL(fputype)	| Do we have an FPU?
1051	jeq	Lswnofpsave		| No  Then don't attempt save.
1052	lea	%a1@(PCB_FPCTX),%a2	| pointer to FP save area
1053	fsave	%a2@			| save FP state
1054	tstb	%a2@			| null state frame?
1055	jeq	Lswnofpsave		| yes, all done
1056	fmovem	%fp0-%fp7,%a2@(216)	| save FP general registers
1057	fmovem	%fpcr/%fpsr/%fpi,%a2@(312)	| save FP control registers
1058Lswnofpsave:
1059
1060	clrl	%a0@(P_BACK)		| clear back link
1061	movb	%a0@(P_MD_FLAGS+3),mdpflag | low byte of p_md.md_flags
1062	movl	%a0@(P_ADDR),%a1		| get p_addr
1063	movl	%a1,_C_LABEL(curpcb)
1064
1065	/*
1066	 * Activate process's address space.
1067	 * XXX Should remember the last USTP value loaded, and call this
1068	 * XXX only if it has changed.
1069	 */
1070	pea	%a0@			| push proc
1071	jbsr	_C_LABEL(pmap_activate)	| pmap_activate(p)
1072	addql	#4,%sp
1073	movl	_C_LABEL(curpcb),%a1	| restore p_addr
1074
1075	lea	_ASM_LABEL(tmpstk),%sp	| now goto a tmp stack for NMI
1076
1077	moveml	%a1@(PCB_REGS),#0xFCFC	| and registers
1078	movl	%a1@(PCB_USP),%a0
1079	movl	%a0,%usp			| and USP
1080
1081	tstl	_C_LABEL(fputype)	| If we don't have an FPU,
1082	jeq	Lnofprest		|  don't try to restore it.
1083	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
1084	tstb	%a0@			| null state frame?
1085	jeq	Lresfprest		| yes, easy
1086#if defined(M68040)
1087#if defined(M68020) || defined(M68030)
1088	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1089	jne	Lresnot040		| no, skip
1090#endif
1091	clrl	%sp@-			| yes...
1092	frestore %sp@+			| ...magic!
1093Lresnot040:
1094#endif
1095	fmovem	%a0@(312),%fpcr/%fpsr/%fpi	| restore FP control registers
1096	fmovem	%a0@(216),%fp0-%fp7	| restore FP general registers
1097Lresfprest:
1098	frestore %a0@			| restore state
1099
1100Lnofprest:
1101	movw	%a1@(PCB_PS),%sr		| no, restore PS
1102	moveq	#1,%d0			| return 1 (for alternate returns)
1103	rts
1104
1105/*
1106 * savectx(pcb)
1107 * Update pcb, saving current processor state.
1108 */
1109ENTRY(savectx)
1110	movl	%sp@(4),%a1
1111	movw	%sr,%a1@(PCB_PS)
1112	movl	%usp,%a0			| grab USP
1113	movl	%a0,%a1@(PCB_USP)		| and save it
1114	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
1115
1116	tstl	_C_LABEL(fputype)	| Do we have FPU?
1117	jeq	Lsvnofpsave		| No?  Then don't save state.
1118	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
1119	fsave	%a0@			| save FP state
1120	tstb	%a0@			| null state frame?
1121	jeq	Lsvnofpsave		| yes, all done
1122	fmovem	%fp0-%fp7,%a0@(216)	| save FP general registers
1123	fmovem	%fpcr/%fpsr/%fpi,%a0@(312)	| save FP control registers
1124Lsvnofpsave:
1125	moveq	#0,%d0			| return 0
1126	rts
1127
1128#if defined(M68040)
1129ENTRY(suline)
1130	movl	%sp@(4),%a0		| address to write
1131	movl	_C_LABEL(curpcb),%a1	| current pcb
1132	movl	#Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault
1133	movl	%sp@(8),%a1		| address of line
1134	movl	%a1@+,%d0			| get lword
1135	movsl	%d0,%a0@+			| put lword
1136	nop				| sync
1137	movl	%a1@+,%d0			| get lword
1138	movsl	%d0,%a0@+			| put lword
1139	nop				| sync
1140	movl	%a1@+,%d0			| get lword
1141	movsl	%d0,%a0@+			| put lword
1142	nop				| sync
1143	movl	%a1@+,%d0			| get lword
1144	movsl	%d0,%a0@+			| put lword
1145	nop				| sync
1146	moveq	#0,%d0			| indicate no fault
1147	jra	Lsldone
1148Lslerr:
1149	moveq	#-1,%d0
1150Lsldone:
1151	movl	_C_LABEL(curpcb),%a1	| current pcb
1152	clrl	%a1@(PCB_ONFAULT) 	| clear fault address
1153	rts
1154#endif
1155
1156ENTRY_NOPROFILE(getsfc)
1157	movc	%sfc,%d0
1158	rts
1159
1160ENTRY_NOPROFILE(getdfc)
1161	movc	%dfc,%d0
1162	rts
1163
1164/*
1165 * Load a new user segment table pointer.
1166 */
1167ENTRY(loadustp)
1168#if defined(M68K_MMU_MOTOROLA)
1169	tstl	_C_LABEL(mmutype)	| HP MMU?
1170	jeq	Lhpmmu9			| yes, skip
1171	movl	%sp@(4),%d0		| new USTP
1172	moveq	#PGSHIFT,%d1
1173	lsll	%d1,%d0			| convert to addr
1174#if defined(M68040)
1175	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1176	jne	LmotommuC		| no, skip
1177	.word	0xf518			| yes, pflusha
1178	.long	0x4e7b0806		| movc %d0,%urp
1179	rts
1180LmotommuC:
1181#endif
1182	pflusha				| flush entire TLB
1183	lea	_C_LABEL(protorp),%a0	| CRP prototype
1184	movl	%d0,%a0@(4)		| stash USTP
1185	pmove	%a0@,%crp			| load root pointer
1186	movl	#CACHE_CLR,%d0
1187	movc	%d0,%cacr			| invalidate cache(s)
1188	rts
1189Lhpmmu9:
1190#endif
1191#if defined(M68K_MMU_HP)
1192	movl	#CACHE_CLR,%d0
1193	movc	%d0,%cacr			| invalidate cache(s)
1194	MMUADDR(%a0)
1195	movl	%a0@(MMUTBINVAL),%d1	| invalidate TLB
1196	tstl	_C_LABEL(ectype)	| have external VAC?
1197	jle	1f			| no, skip
1198	andl	#~MMU_CEN,%a0@(MMUCMD)	| toggle cache enable
1199	orl	#MMU_CEN,%a0@(MMUCMD)	| to clear data cache
12001:
1201	movl	%sp@(4),%a0@(MMUUSTP)	| load a new USTP
1202#endif
1203	rts
1204
1205ENTRY(ploadw)
1206#if defined(M68K_MMU_MOTOROLA)
1207	movl	%sp@(4),%a0		| address to load
1208#if defined(M68K_MMU_HP)
1209	tstl	_C_LABEL(mmutype)	| HP MMU?
1210	jeq	Lploadwskp		| yes, skip
1211#endif
1212#if defined(M68040)
1213	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040?
1214	jeq	Lploadwskp		| yes, skip
1215#endif
1216	ploadw	#1,%a0@			| pre-load translation
1217Lploadwskp:
1218#endif
1219	rts
1220
1221/*
1222 * Set processor priority level calls.  Most are implemented with
1223 * inline asm expansions.  However, spl0 requires special handling
1224 * as we need to check for our emulated software interrupts.
1225 */
1226
1227ENTRY(spl0)
1228	moveq	#0,%d0
1229	movw	%sr,%d0			| get old SR for return
1230	movw	#PSL_LOWIPL,%sr		| restore new SR
1231	tstb	_C_LABEL(ssir)		| software interrupt pending?
1232	jeq	Lspldone		| no, all done
1233	subql	#4,%sp			| make room for RTE frame
1234	movl	%sp@(4),%sp@(2)		| position return address
1235	clrw	%sp@(6)			| set frame type 0
1236	movw	#PSL_LOWIPL,%sp@		| and new SR
1237	jra	Lgotsir			| go handle it
1238Lspldone:
1239	rts
1240
1241/*
1242 * _delay(u_int N)
1243 *
1244 * Delay for at least (N/256) microsecends.
1245 * This routine depends on the variable:  delay_divisor
1246 * which should be set based on the CPU clock rate.
1247 */
1248ENTRY_NOPROFILE(_delay)
1249	| d0 = arg = (usecs << 8)
1250	movl	%sp@(4),%d0
1251	| d1 = delay_divisor
1252	movl	_C_LABEL(delay_divisor),%d1
1253L_delay:
1254	subl	%d1,%d0
1255	jgt	L_delay
1256	rts
1257
1258/*
1259 * Save and restore 68881 state.
1260 * Pretty awful looking since our assembler does not
1261 * recognize FP mnemonics.
1262 */
1263ENTRY(m68881_save)
1264	movl	%sp@(4),%a0		| save area pointer
1265	fsave	%a0@			| save state
1266	tstb	%a0@			| null state frame?
1267	jeq	Lm68881sdone		| yes, all done
1268	fmovem	%fp0-%fp7,%a0@(216)	| save FP general registers
1269	fmovem	%fpcr/%fpsr/%fpi,%a0@(312)	| save FP control registers
1270Lm68881sdone:
1271	rts
1272
1273ENTRY(m68881_restore)
1274	movl	%sp@(4),%a0		| save area pointer
1275	tstb	%a0@			| null state frame?
1276	jeq	Lm68881rdone		| yes, easy
1277	fmovem	%a0@(312),%fpcr/%fpsr/%fpi	| restore FP control registers
1278	fmovem	%a0@(216),%fp0-%fp7	| restore FP general registers
1279Lm68881rdone:
1280	frestore %a0@			| restore state
1281	rts
1282
1283ENTRY_NOPROFILE(doboot)
1284	movl #0x5c00c060, %d0		| want phys addressing
1285	.long	0x4e7b0006		| movc d0,dtt0
1286	movl	#1, 0x5c00b800		| reset
1287	stop	#0x2700			| paranoia
1288
1289	.data
1290GLOBAL(mmutype)
1291	.long	MMU_HP		| default to HP MMU
1292GLOBAL(cputype)
1293	.long	CPU_68020	| default to 68020 CPU
1294GLOBAL(fputype)
1295	.long	FPU_68881	| default to 68881 FPU
1296GLOBAL(protorp)
1297	.long	0,0		| prototype root pointer
1298GLOBAL(prototc)
1299	.long	0		| prototype translation control
1300GLOBAL(want_resched)
1301	.long	0
1302
1303GLOBAL(proc0paddr)
1304	.long	0		| KVA of proc0 u-area
1305#ifdef DEBUG
1306	.globl	fulltflush, fullcflush
1307fulltflush:
1308	.long	0
1309fullcflush:
1310	.long	0
1311#endif
1312
1313/* interrupt counters */
1314GLOBAL(intrnames)
1315	.asciz	"spur"
1316	.asciz	"lev1"
1317	.asciz	"lev2"
1318	.asciz	"lev3"
1319	.asciz	"lev4"
1320	.asciz	"lev5"
1321	.asciz	"clock"
1322	.asciz	"nmi"
1323GLOBAL(eintrnames)
1324	.even
1325GLOBAL(intrcnt)
1326	.long	0,0,0,0,0,0,0,0
1327GLOBAL(eintrcnt)
1328