xref: /netbsd/sys/arch/news68k/news68k/locore.s (revision c4a72b64)
1/*	$NetBSD: locore.s,v 1.27 2002/11/02 20:03:07 chs Exp $	*/
2
3/*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1980, 1990, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the University of
23 *	California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: Utah $Hdr: locore.s 1.66 92/12/22$
41 *
42 *	@(#)locore.s	8.6 (Berkeley) 5/27/94
43 */
44
45/*
46 * locore.s for news68k - based on mvme68k and hp300 version
47 */
48
49#include "opt_compat_netbsd.h"
50#include "opt_compat_svr4.h"
51#include "opt_compat_sunos.h"
52#include "opt_fpsp.h"
53#include "opt_ddb.h"
54#include "opt_kgdb.h"
55#include "opt_lockdebug.h"
56
57#include "assym.h"
58#include <machine/asm.h>
59#include <machine/trap.h>
60
61
62/*
63 * Temporary stack for a variety of purposes.
64 * Try and make this the first thing is the data segment so it
65 * is page aligned.  Note that if we overflow here, we run into
66 * our text segment.
67 */
68	.data
69	.space	NBPG
70ASLOCAL(tmpstk)
71
72ASLOCAL(monitor_vbr)
73	.long	0
74
75ASLOCAL(monitor)
76	.long	0
77
78#include <news68k/news68k/vectors.s>
79
80
81/*
82 * Macro to relocate a symbol, used before MMU is enabled.
83 */
84#define	_RELOC(var, ar)		\
85	lea	var,ar;		\
86	addl	%a5,ar
87
88#define	RELOC(var, ar)		_RELOC(_C_LABEL(var), ar)
89#define	ASRELOC(var, ar)	_RELOC(_ASM_LABEL(var), ar)
90
91/*
92 * LED control for DEBUG.
93 */
94#ifdef __STDC__
95#define	IMMEDIATE	#
96#define	SETLED(func)	\
97	movl	IMMEDIATE func,%d0; \
98	jmp	debug_led
99
100#define	SETLED2(func)	\
101	movl	IMMEDIATE func,%d0; \
102	jmp	debug_led2
103#else
104#define	SETLED(func)	\
105	movl	#func,%d0; \
106	jmp	debug_led
107
108#define	SETLED2(func)	\
109	movl	#func,%d0; \
110	jmp	debug_led2
111#endif /* __STDC__ */
112
113#define	TOMONITOR	\
114	moveal	_ASM_LABEL(monitor), %a0; \
115	jmp	%a0@
116/*
117 * Initialization
118 *
119 * The bootstrap loader loads us in starting at 0, and VBR is non-zero.
120 * On entry, args on stack are boot device, boot filename, console unit,
121 * boot flags (howto), boot device name, filesystem type name.
122 */
123BSS(lowram,4)
124BSS(esym,4)
125
126/*
127 * This is for kvm_mkdb, and should be the address of the beginning
128 * of the kernel text segment (not necessarily the same as kernbase).
129 */
130	.text
131GLOBAL(kernel_text)
132
133/*
134 * start of kernel and .text!
135 */
136ASENTRY_NOPROFILE(start)
137	movw	#PSL_HIGHIPL,%sr	| no interrupts
138
139	movl	#0x0, %a5		| RAM starts at 0 (%a5)
140	movl	#0x0, %a6		| clear %fp to terminate debug trace
141
142	RELOC(bootdev,%a0)
143	movl	%d6, %a0@		| save bootdev
144	RELOC(boothowto,%a0)
145	movl	%d7, %a0@		| save boothowto
146
147	ASRELOC(tmpstk,%a0)
148	movl	%a0,%sp			| give ourselves a temporary stack
149
150	movc %vbr,%a0
151	movl %a0@(188),_ASM_LABEL(monitor)| save trap #15 to return PROM monitor
152
153	RELOC(esym, %a0)
154#ifdef DDB
155	movl	%d2,%a0@		| store end of symbol table
156#else
157	clrl	%a0@
158#endif
159	/* %d2 now free */
160	RELOC(lowram, %a0)
161	movl	%a5,%a0			| store start of physical memory
162	movl	#CACHE_OFF,%d0
163	movc	%d0,%cacr		| clear and disable on-chip cache(s)
164
165	movl	#DC_FREEZE,%d0		| data freeze bit
166	movc	%d0,%cacr		|  only exists on 68030
167	movc	%cacr,%d0		| read it back
168	tstl	%d0			| zero?
169	jeq	Lnot68030		| yes, we have 68020/68040
170
171	movl	#CACHE_OFF,%d0
172	movc	%d0,%cacr		| clear data freeze bit
173
174	RELOC(mmutype,%a0)
175	movl	#MMU_68030,%a0@
176	RELOC(cputype,%a0)
177	movl	#CPU_68030,%a0@
178	RELOC(fputype,%a0)
179	movl	#FPU_68882,%a0@
180
181	movl	%d6,%d0			| check bootdev
182	andl	#0x00007000,%d0		| BOOTDEV_HOST
183	cmpl	#0x00007000,%d0		| news1200?
184	jne	Lnot1200		| no, then skip
185
186	/* news1200 */
187	/* XXX Are these needed?*/
188	sf	0xe1100000		| AST disable (???)
189	sf	0xe10c0000		| level2 interrupt disable (???)
190	moveb	#0x03,0xe1140002	| timer set (???)
191	moveb	#0xd0,0xe1140003	| timer set (???)
192	sf	0xe1140000		| timer interrupt disable (???)
193	/* XXX */
194
195	RELOC(systype,%a0)
196	movl	#NEWS1200,%a0@
197	RELOC(ectype, %a0)		|
198	movl	#EC_NONE,%a0@		| news1200 have no L2 cache
199
200	/*
201	 * Fix up the physical addresses of the news1200's onboard
202	 * I/O registers.
203	 */
204	RELOC(intiobase_phys, %a0);
205	movl	#INTIOBASE1200,%a0@
206	RELOC(intiotop_phys, %a0);
207	movl	#INTIOTOP1200,%a0@
208
209	RELOC(extiobase_phys, %a0);
210	movl	#EXTIOBASE1200,%a0@
211	RELOC(extiotop_phys, %a0);
212	movl	#EXTIOTOP1200,%a0@
213
214	RELOC(ctrl_power, %a0);
215	movl	#0xe1000000,%a0@	| CTRL_POWER port for news1200
216	jra	Lcom030
217
218Lnot1200:
219	tstl	%d0			| news1400/1500/1600/1700?
220	jne	Lnotyet			| no, then skip
221
222	/* news1400/1500/1600/1700 */
223	/* XXX Are these needed?*/
224	sf	0xe1280000		| AST disable (???)
225	sf	0xe1180000		| level2 interrupt disable (???)
226	st	0xe1300000		| L2 cache enable (???)
227	st	0xe1900000		| L2 cache clear (???)
228	sf	0xe1000000		| timer interrupt disable (???)
229	moveb	#0x36,0xe0c80000	| XXX reset FDC for PWS-1560
230	/* XXX */
231
232	/* news1400/1500/1600/1700 - 68030 CPU/MMU, 68882 FPU */
233	RELOC(systype,%a0)
234	movl	#NEWS1700,%a0@
235
236	cmpb	#0xf2,0xe1c00000	| read model id from idrom
237	jle	1f			|  news1600/1700 ?
238
239	RELOC(ectype, %a0)		| no, we are news1400/1500
240	movl	#EC_NONE,%a0		|  and do not have L2 cache
241	jra	2f
2421:
243	RELOC(ectype, %a0)		| yes, we are news1600/1700
244	movl	#EC_PHYS,%a0@		|  and have a physical address cache
2452:
246	/*
247	 * Fix up the physical addresses of the news1700's onboard
248	 * I/O registers.
249	 */
250	RELOC(intiobase_phys, %a0);
251	movl	#INTIOBASE1700,%a0@
252	RELOC(intiotop_phys, %a0);
253	movl	#INTIOTOP1700,%a0@
254
255	RELOC(extiobase_phys, %a0);
256	movl	#EXTIOBASE1700,%a0@
257	RELOC(extiotop_phys, %a0);
258	movl	#EXTIOTOP1700,%a0@
259
260	RELOC(ctrl_power, %a0);
261	movl	#0xe1380000,%a0@	| CTRL_POWER port for news1700
262Lcom030:
263
264	RELOC(vectab,%a0)
265	RELOC(busaddrerr2030,%a1)
266	movl	%a1,%a0@(8)
267	movl	%a1,%a0@(12)
268
269	movl	%d4,%d1
270	addl	%a5,%d1
271	moveq	#PGSHIFT,%d2
272	lsrl	%d2,%d1			| convert to page (click) number
273	RELOC(maxmem, %a0)
274	movl	%d1,%a0@		| save as maxmem
275
276	movl	%d4,%d1			|
277	moveq	#PGSHIFT,%d2
278	lsrl	%d2,%d1			| convert to page (click) number
279	RELOC(physmem, %a0)
280	movl	%d1,%a0@		| save as physmem
281
282	jra	Lstart1
283Lnot68030:
284
285#ifdef news700 /* XXX eventually... */
286	RELOC(mmutype,%a0)
287	movl	#MMU_68851,%a0@
288	RELOC(cputype,%a0)
289	movl	#CPU_68020,%a0@
290	RELOC(fputype,%a0)
291	movl	#FPU_68881,%a0@
292	RELOC(ectype, %a0)
293	movl	#EC_NONE,%a0@
294#if 1	/* XXX */
295	jra	Lnotyet
296#else
297	/* XXX more XXX */
298	jra	Lstart1
299#endif
300Lnot700:
301#endif
302
303	/*
304	 * If we fall to here, the board is not supported.
305	 * Just drop out to the monitor.
306	 */
307
308	TOMONITOR
309	/* NOTREACHED */
310
311Lnotyet:
312	/*
313	 * If we get here, it means a particular model
314	 * doesn't have the necessary support code in the
315	 * kernel.  Just drop out to the monitor.
316	 */
317	TOMONITOR
318	/* NOTREACHED */
319
320Lstart1:
321/* initialize source/destination control registers for movs */
322	moveq	#FC_USERD,%d0		| user space
323	movc	%d0,%sfc		|   as source
324	movc	%d0,%dfc		|   and destination of transfers
325/*
326 * configure kernel and proc0 VA space so we can get going
327 */
328	.globl	_Sysseg, _pmap_bootstrap, _avail_start
329
330#ifdef DDB
331	RELOC(esym,%a0)			| end of static kernel test/data/syms
332	movl	%a0@,%d2
333	jne	Lstart2
334#endif
335	RELOC(end,%a0)
336	movl	%a0,%d2			| end of static kernel text/data
337Lstart2:
338	addl	#NBPG-1,%d2
339	andl	#PG_FRAME,%d2		| round to a page
340	movl	%d2,%a4
341	addl	%a5,%a4			| convert to PA
342#if 0
343	movl	#0x0, %sp@-		| firstpa
344#else
345	pea	%a5@
346#endif
347	pea	%a4@			| nextpa
348	RELOC(pmap_bootstrap,%a0)
349	jbsr	%a0@			| pmap_bootstrap(firstpa, nextpa)
350	addql	#8,%sp
351/*
352 * Enable the MMU.
353 * Since the kernel is mapped logical == physical, we just turn it on.
354 */
355	movc	%vbr,%d0		| Preserve monitor's VBR address
356	movl	%d0,_ASM_LABEL(monitor_vbr)
357
358	movl	#_C_LABEL(vectab),%d0	| get our VBR address
359	movc	%d0,%vbr
360
361	RELOC(Sysseg, %a0)		| system segment table addr
362	movl	%a0@,%d1		| read value (a KVA)
363	addl	%a5,%d1			| convert to PA
364	RELOC(mmutype, %a0)
365	cmpl	#MMU_68040,%a0@		| 68040?
366	jne	Lmotommu1		| no, skip
367	.long	0x4e7b1807		| movc %d1,%srp
368	jra	Lstploaddone
369Lmotommu1:
370	RELOC(protorp, %a0)
371	movl	#0x80000202,%a0@	| nolimit + share global + 4 byte PTEs
372	movl	%d1,%a0@(4)		| + segtable address
373	pmove	%a0@,%srp		| load the supervisor root pointer
374	movl	#0x80000002,%a0@	| reinit upper half for CRP loads
375Lstploaddone:
376	RELOC(mmutype, %a0)
377	cmpl	#MMU_68040,%a0@		| 68040?
378	jne	Lmotommu2		| no, skip
379	moveq	#0,%d0			| ensure TT regs are disabled
380	.long	0x4e7b0004		| movc %d0,%itt0
381	.long	0x4e7b0005		| movc %d0,%itt1
382	.long	0x4e7b0006		| movc %d0,%dtt0
383	.long	0x4e7b0007		| movc %d0,%dtt1
384	.word	0xf4d8			| cinva bc
385	.word	0xf518			| pflusha
386	movl	#0x8000,%d0
387	.long	0x4e7b0003		| movc %d0,%tc
388	movl	#CACHE40_ON,%d0
389	movc	%d0,%cacr		| turn on both caches
390	jmp	Lenab1
391Lmotommu2:
392#if 1 /* XXX use %tt0 register to map I/O space temporary */
393	RELOC(protott0, %a0)
394	movl	#0xe01f8550,%a0@	| use %tt0 (0xe0000000-0xffffffff)
395	.long	0xf0100800		| pmove %a0@,%tt0
396#endif
397	RELOC(prototc, %a2)
398	movl	#0x82c0aa00,%a2@	| value to load TC with
399	pmove	%a2@,%tc		| load it
400
401/*
402 * Should be running mapped from this point on
403 */
404Lenab1:
405/* select the software page size now */
406	lea	_ASM_LABEL(tmpstk),%sp	| temporary stack
407	jbsr	_C_LABEL(uvm_setpagesize)  | select software page size
408/* set kernel stack, user SP, and initial pcb */
409	movl	_C_LABEL(proc0paddr),%a1| get proc0 pcb addr
410	lea	%a1@(USPACE-4),%sp	| set kernel stack to end of area
411	lea	_C_LABEL(proc0),%a2	| initialize proc0.p_addr so that
412	movl	%a1,%a2@(P_ADDR)	|   we don't deref NULL in trap()
413	movl	#USRSTACK-4,%a2
414	movl	%a2,%usp		| init user SP
415	movl	%a1,_C_LABEL(curpcb)	| proc0 is running
416
417	tstl	_C_LABEL(fputype)	| Have an FPU?
418	jeq	Lenab2			| No, skip.
419	clrl	%a1@(PCB_FPCTX)		| ensure null FP context
420	movl	%a1,%sp@-
421	jbsr	_C_LABEL(m68881_restore) | restore it (does not kill a1)
422	addql	#4,%sp
423Lenab2:
424	jbsr	_C_LABEL(_TBIA)		| invalidate TLB
425	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
426	jeq	Ltbia040		| yes, cache already on
427	pflusha
428	tstl	_C_LABEL(mmutype)
429	jpl	Lenab3			| 68851 implies no d-cache
430	movl	#CACHE_ON,%d0
431	tstl	_C_LABEL(ectype)	| have external cache?
432	jne	1f			| Yes, skip
433	orl	#CACHE_BE,%d0		| set cache burst enable
4341:
435	movc	%d0,%cacr		| clear cache
436	tstl	_C_LABEL(ectype)	| have external cache?
437	jeq	Lenab3			| No, skip
438	movl	_C_LABEL(cache_clr),%a0
439	st	%a0@			| flush external cache
440	jra	Lenab3
441Ltbia040:
442	.word	0xf518
443Lenab3:
444/* final setup for C code */
445	jbsr	_C_LABEL(news68k_init)	| additional pre-main initialization
446
447/*
448 * Create a fake exception frame so that cpu_fork() can copy it.
449 * main() nevers returns; we exit to user mode from a forked process
450 * later on.
451 */
452	clrw	%sp@-			| vector offset/frame type
453	clrl	%sp@-			| PC - filled in by "execve"
454	movw	#PSL_USER,%sp@-		| in user mode
455	clrl	%sp@-			| stack adjust count and padding
456	lea	%sp@(-64),%sp		| construct space for D0-D7/A0-A7
457	lea	_C_LABEL(proc0),%a0	| save pointer to frame
458	movl	%sp,%a0@(P_MD_REGS)	|   in proc0.p_md.md_regs
459
460	jra	_C_LABEL(main)		| main()
461
462	SETLED2(3);			| main returned?
463
464/*
465 * proc_trampoline: call function in register a2 with a3 as an arg
466 * and then rei.
467 */
468GLOBAL(proc_trampoline)
469	movl	%a3,%sp@-		| push function arg
470	jbsr	%a2@			| call function
471	addql	#4,%sp			| pop arg
472	movl	%sp@(FR_SP),%a0		| grab and load
473	movl	%a0,%usp		|   user SP
474	moveml	%sp@+,#0x7FFF		| restore most user regs
475	addql	#8,%sp			| toss SP and stack adjust
476	jra	_ASM_LABEL(rei)		| and return
477
478/*
479 * Trap/interrupt vector routines
480 */
481#include <m68k/m68k/trap_subr.s>
482
483	.data
484GLOBAL(m68k_fault_addr)
485	.long	0
486
487#if defined(M68020) || defined(M68030)
488ENTRY_NOPROFILE(busaddrerr2030)
489	clrl	%sp@-			| stack adjust count
490	moveml	#0xFFFF,%sp@-		| save user registers
491	movl	%usp,%a0		| save the user SP
492	movl	%a0,%sp@(FR_SP)		|   in the savearea
493	moveq	#0,%d0
494	movw	%sp@(FR_HW+10),%d0	| grab SSW for fault processing
495	btst	#12,%d0			| RB set?
496	jeq	LbeX0			| no, test RC
497	bset	#14,%d0			| yes, must set FB
498	movw	%d0,%sp@(FR_HW+10)	| for hardware too
499LbeX0:
500	btst	#13,%d0			| RC set?
501	jeq	LbeX1			| no, skip
502	bset	#15,%d0			| yes, must set FC
503	movw	%d0,%sp@(FR_HW+10)	| for hardware too
504LbeX1:
505	btst	#8,%d0			| data fault?
506	jeq	Lbe0			| no, check for hard cases
507	movl	%sp@(FR_HW+16),%d1	| fault address is as given in frame
508	jra	Lbe10			| thats it
509Lbe0:
510	btst	#4,%sp@(FR_HW+6)	| long (type B) stack frame?
511	jne	Lbe4			| yes, go handle
512	movl	%sp@(FR_HW+2),%d1	| no, can use save PC
513	btst	#14,%d0			| FB set?
514	jeq	Lbe3			| no, try FC
515	addql	#4,%d1			| yes, adjust address
516	jra	Lbe10			| done
517Lbe3:
518	btst	#15,%d0			| FC set?
519	jeq	Lbe10			| no, done
520	addql	#2,%d1			| yes, adjust address
521	jra	Lbe10			| done
522Lbe4:
523	movl	%sp@(FR_HW+36),%d1	| long format, use stage B address
524	btst	#15,%d0			| FC set?
525	jeq	Lbe10			| no, all done
526	subql	#2,%d1			| yes, adjust address
527Lbe10:
528	movl	%d1,%sp@-		| push fault VA
529	movl	%d0,%sp@-		| and padded SSW
530	movw	%sp@(FR_HW+8+6),%d0	| get frame format/vector offset
531	andw	#0x0FFF,%d0		| clear out frame format
532	cmpw	#12,%d0			| address error vector?
533	jeq	Lisaerr			| yes, go to it
534	movl	%d1,%a0			| fault address
535	movl	%sp@,%d0		| function code from ssw
536	btst	#8,%d0			| data fault?
537	jne	Lbe10a
538#if 0
539	movql	#1,%d0			| user program access FC
540#else
541	moveq	#1,%d0			| user program access FC
542#endif
543					| (we dont separate data/program)
544	btst	#5,%sp@(FR_HW+8)	| supervisor mode?
545	jeq	Lbe10a			| if no, done
546	movql	#5,%d0			| else supervisor program access
547Lbe10a:
548	ptestr	%d0,%a0@,#7		| do a table search
549	pmove	%psr,%sp@		| save result
550	movb	%sp@,%d1
551	btst	#2,%d1			| invalid (incl. limit viol. and berr)?
552	jeq	Lmightnotbemerr		| no -> wp check
553	btst	#7,%d1			| is it MMU table berr?
554	jne	Lisberr1		| yes, needs not be fast.
555Lismerr:
556	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
557	jra	_ASM_LABEL(faultstkadj)	| and deal with it
558Lmightnotbemerr:
559	btst	#3,%d1			| write protect bit set?
560	jeq	Lisberr1		| no: must be bus error
561	movl	%sp@,%d0		| ssw into low word of %d0
562	andw	#0xc0,%d0		| Write protect is set on page:
563	cmpw	#0x40,%d0		| was it read cycle?
564	jne	Lismerr			| no, was not WPE, must be MMU fault
565	jra	Lisberr1		| real bus err needs not be fast.
566Lisaerr:
567	movl	#T_ADDRERR,%sp@-	| mark address error
568	jra	_ASM_LABEL(faultstkadj)	| and deal with it
569Lisberr1:
570	clrw	%sp@			| re-clear pad word
571	tstl	_C_LABEL(nofault)	| catch bus error?
572	jeq	Lisberr			| no, handle as usual
573	movl	%sp@(FR_HW+8+16),_C_LABEL(m68k_fault_addr) | save fault addr
574	movl	_C_LABEL(nofault),%sp@-	| yes,
575	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
576	/* NOTREACHED */
577#endif /* M68020 || M68030 */
578
579Lisberr:				| also used by M68040/60
580	movl	#T_BUSERR,%sp@-		| mark bus error
581	jra	_ASM_LABEL(faultstkadj)	| and deal with it
582
583/*
584 * FP exceptions.
585 */
586ENTRY_NOPROFILE(fpfline)
587#ifdef FPU_EMULATE
588	clrl	%sp@-			| stack adjust count
589	moveml	#0xFFFF,%sp@-		| save registers
590	moveq	#T_FPEMULI,%d0		| denote as FP emulation trap
591	jra	_ASM_LABEL(fault)	| do it
592#else
593	jra	_C_LABEL(illinst)
594#endif
595
596ENTRY_NOPROFILE(fpunsupp)
597#ifdef FPU_EMULATE
598	clrl	%sp@-			| stack adjust count
599	moveml	#0xFFFF,%sp@-		| save registers
600	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
601	jra	_ASM_LABEL(fault)	| do it
602#else
603	jra	_C_LABEL(illinst)
604#endif
605
606/*
607 * Handles all other FP coprocessor exceptions.
608 * Note that since some FP exceptions generate mid-instruction frames
609 * and may cause signal delivery, we need to test for stack adjustment
610 * after the trap call.
611 */
612ENTRY_NOPROFILE(fpfault)
613	clrl	%sp@-		| stack adjust count
614	moveml	#0xFFFF,%sp@-	| save user registers
615	movl	%usp,%a0	| and save
616	movl	%a0,%sp@(FR_SP)	|   the user stack pointer
617	clrl	%sp@-		| no VA arg
618	movl	_C_LABEL(curpcb),%a0 | current pcb
619	lea	%a0@(PCB_FPCTX),%a0 | address of FP savearea
620	fsave	%a0@		| save state
621	tstb	%a0@		| null state frame?
622	jeq	Lfptnull	| yes, safe
623	clrw	%d0		| no, need to tweak BIU
624	movb	%a0@(1),%d0	| get frame size
625	bset	#3,%a0@(0,%d0:w)| set exc_pend bit of BIU
626Lfptnull:
627	fmovem	%fpsr,%sp@-	| push fpsr as code argument
628	frestore %a0@		| restore state
629	movl	#T_FPERR,%sp@-	| push type arg
630	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
631
632
633/*
634 * Other exceptions only cause four and six word stack frame and require
635 * no post-trap stack adjustment.
636 */
637
638ENTRY_NOPROFILE(badtrap)
639	moveml	#0xC0C0,%sp@-		| save scratch regs
640	movw	%sp@(22),%sp@-		| push exception vector info
641	clrw	%sp@-
642	movl	%sp@(22),%sp@-		| and PC
643	jbsr	_C_LABEL(straytrap)	| report
644	addql	#8,%sp			| pop args
645	moveml	%sp@+,#0x0303		| restore regs
646	jra	_ASM_LABEL(rei)		| all done
647
648ENTRY_NOPROFILE(trap0)
649	clrl	%sp@-			| stack adjust count
650	moveml	#0xFFFF,%sp@-		| save user registers
651	movl	%usp,%a0		| save the user SP
652	movl	%a0,%sp@(FR_SP)		|   in the savearea
653	movl	%d0,%sp@-		| push syscall number
654	jbsr	_C_LABEL(syscall)	| handle it
655	addql	#4,%sp			| pop syscall arg
656	tstl	_C_LABEL(astpending)
657	jne	Lrei2
658	movl	%sp@(FR_SP),%a0		| grab and restore
659	movl	%a0,%usp		|   user SP
660	moveml	%sp@+,#0x7FFF		| restore most registers
661	addql	#8,%sp			| pop SP and stack adjust
662	rte
663
664/*
665 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
666 *	cachectl(command, addr, length)
667 * command in %d0, addr in %a1, length in %d1
668 */
669ENTRY_NOPROFILE(trap12)
670	movl	_C_LABEL(curproc),%sp@-	| push curproc pointer
671	movl	%d1,%sp@-		| push length
672	movl	%a1,%sp@-		| push addr
673	movl	%d0,%sp@-		| push command
674	jbsr	_C_LABEL(cachectl1)	| do it
675	lea	%sp@(16),%sp		| pop args
676	jra	_ASM_LABEL(rei)		| all done
677
678/*
679 * Trace (single-step) trap.  Kernel-mode is special.
680 * User mode traps are simply passed on to trap().
681 */
682ENTRY_NOPROFILE(trace)
683	clrl	%sp@-			| stack adjust count
684	moveml	#0xFFFF,%sp@-
685	moveq	#T_TRACE,%d0
686
687	| Check PSW and see what happen.
688	|   T=0 S=0	(should not happen)
689	|   T=1 S=0	trace trap from user mode
690	|   T=0 S=1	trace trap on a trap instruction
691	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
692
693	movw	%sp@(FR_HW),%d1		| get PSW
694	notw	%d1			| XXX no support for T0 on 680[234]0
695	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
696	jeq	Lkbrkpt			| yes, kernel breakpoint
697	jra	_ASM_LABEL(fault)	| no, user-mode fault
698
699/*
700 * Trap 15 is used for:
701 *	- GDB breakpoints (in user programs)
702 *	- KGDB breakpoints (in the kernel)
703 *	- trace traps for SUN binaries (not fully supported yet)
704 * User mode traps are simply passed to trap().
705 */
706ENTRY_NOPROFILE(trap15)
707	clrl	%sp@-			| stack adjust count
708	moveml	#0xFFFF,%sp@-
709	moveq	#T_TRAP15,%d0
710	movw	%sp@(FR_HW),%d1		| get PSW
711	andw	#PSL_S,%d1		| from system mode?
712	jne	Lkbrkpt			| yes, kernel breakpoint
713	jra	_ASM_LABEL(fault)	| no, user-mode fault
714
715Lkbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type)
716	| Save the system sp rather than the user sp.
717	movw	#PSL_HIGHIPL,%sr	| lock out interrupts
718	lea	%sp@(FR_SIZE),%a6	| Save stack pointer
719	movl	%a6,%sp@(FR_SP)		|  from before trap
720
721	| If were are not on tmpstk switch to it.
722	| (so debugger can change the stack pointer)
723	movl	%a6,%d1
724	cmpl	#_ASM_LABEL(tmpstk),%d1
725	jls	Lbrkpt2			| already on tmpstk
726	| Copy frame to the temporary stack
727	movl	%sp,%a0			| a0=src
728	lea	_ASM_LABEL(tmpstk)-96,%a1 | a1=dst
729	movl	%a1,%sp			| sp=new frame
730	movql	#FR_SIZE,%d1
731Lbrkpt1:
732	movl	%a0@+,%a1@+
733	subql	#4,%d1
734	bgt	Lbrkpt1
735
736Lbrkpt2:
737	| Call the trap handler for the kernel debugger.
738	| Do not call trap() to do it, so that we can
739	| set breakpoints in trap() if we want.  We know
740	| the trap type is either T_TRACE or T_BREAKPOINT.
741	| If we have both DDB and KGDB, let KGDB see it first,
742	| because KGDB will just return 0 if not connected.
743	| Save args in %d2, %a2
744	movl	%d0,%d2			| trap type
745	movl	%sp,%a2			| frame ptr
746#ifdef KGDB
747	| Let KGDB handle it (if connected)
748	movl	%a2,%sp@-		| push frame ptr
749	movl	%d2,%sp@-		| push trap type
750	jbsr	_C_LABEL(kgdb_trap)	| handle the trap
751	addql	#8,%sp			| pop args
752	cmpl	#0,%d0			| did kgdb handle it?
753	jne	Lbrkpt3			| yes, done
754#endif
755#ifdef DDB
756	| Let DDB handle it
757	movl	%a2,%sp@-		| push frame ptr
758	movl	%d2,%sp@-		| push trap type
759	jbsr	_C_LABEL(kdb_trap)	| handle the trap
760	addql	#8,%sp			| pop args
761#if 0	/* not needed on hp300 */
762	cmpl	#0,%d0			| did ddb handle it?
763	jne	Lbrkpt3			| yes, done
764#endif
765#endif
766	/* Sun 3 drops into PROM here. */
767Lbrkpt3:
768	| The stack pointer may have been modified, or
769	| data below it modified (by kgdb push call),
770	| so push the hardware frame at the current sp
771	| before restoring registers and returning.
772
773	movl	%sp@(FR_SP),%a0		| modified %sp
774	lea	%sp@(FR_SIZE),%a1	| end of our frame
775	movl	%a1@-,%a0@-		| copy 2 longs with
776	movl	%a1@-,%a0@-		| ... predecrement
777	movl	%a0,%sp@(FR_SP)		| %sp = h/w frame
778	moveml	%sp@+,#0x7FFF		| restore all but %sp
779	movl	%sp@,%sp		| ... and %sp
780	rte				| all done
781
782/*
783 * Use common m68k sigreturn routine.
784 */
785#include <m68k/m68k/sigreturn.s>
786
787/*
788 * Interrupt handlers.
789 *
790 * For auto-vectored interrupts, the CPU provides the
791 * vector 0x18+level.  Note we count spurious interrupts,
792 * but don't do anything else with them.
793 *
794 * _intrhand_autovec is the entry point for auto-vectored
795 * interrupts.
796 *
797 * For vectored interrupts, we pull the pc, evec, and exception frame
798 * and pass them to the vectored interrupt dispatcher.  The vectored
799 * interrupt dispatcher will deal with strays.
800 *
801 * _intrhand_vectored is the entry point for vectored interrupts.
802 */
803
804#define INTERRUPT_SAVEREG	moveml  #0xC0C0,%sp@-
805#define INTERRUPT_RESTOREREG	moveml  %sp@+,#0x0303
806
807ENTRY_NOPROFILE(spurintr)	/* Level 0 */
808	addql	#1,_C_LABEL(intrcnt)+0
809	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
810	rte
811
812ENTRY_NOPROFILE(intrhand_autovec)	/* Levels 1 through 6 */
813	INTERRUPT_SAVEREG
814	movw	%sp@(22),%sp@-		| push exception vector
815	clrw	%sp@-
816	jbsr	_C_LABEL(isrdispatch_autovec) | call dispatcher
817	addql	#4,%sp
818	INTERRUPT_RESTOREREG
819	rte
820
821ENTRY_NOPROFILE(lev1intr)		/* Level 1: AST interrupt */
822	movl	%a0,%sp@-
823	addql	#1,_C_LABEL(intrcnt)+4
824	addql	#1,_C_LABEL(uvmexp)+UVMEXP_INTRS
825	movl	_C_LABEL(ctrl_ast),%a0
826	clrb	%a0@			| disable AST interrupt
827	movl	%sp@+,%a0
828	jra	_ASM_LABEL(rei)		| handle AST
829
830ENTRY_NOPROFILE(lev2intr)		/* Level 2: software interrupt */
831	INTERRUPT_SAVEREG
832	jbsr	_C_LABEL(intrhand_lev2)
833	INTERRUPT_RESTOREREG
834	rte
835
836ENTRY_NOPROFILE(lev3intr)		/* Level 3: fd, lpt, vme etc. */
837	INTERRUPT_SAVEREG
838	jbsr	_C_LABEL(intrhand_lev3)
839	INTERRUPT_RESTOREREG
840	rte
841
842ENTRY_NOPROFILE(lev4intr)		/* Level 4: scsi, le, vme etc. */
843	INTERRUPT_SAVEREG
844	jbsr	_C_LABEL(intrhand_lev4)
845	INTERRUPT_RESTOREREG
846	rte
847
848#if 0
849ENTRY_NOPROFILE(lev5intr)		/* Level 5: kb, ms (zs is vectored) */
850	INTERRUPT_SAVEREG
851	jbsr	_C_LABEL(intrhand_lev5)
852	INTERRUPT_RESTOREREG
853	rte
854#endif
855
856ENTRY_NOPROFILE(_isr_clock)		/* Level 6: clock (see clock_hb.c) */
857	INTERRUPT_SAVEREG
858	lea	%sp@(16),%a1
859	movl	%a1,%sp@-
860	jbsr	_C_LABEL(clock_intr)
861	addql	#4,%sp
862	INTERRUPT_RESTOREREG
863	rte
864
865#if 0
866ENTRY_NOPROFILE(lev7intr)		/* Level 7: NMI */
867	addql	#1,_C_LABEL(intrcnt)+32
868	clrl	%sp@-
869	moveml	#0xFFFF,%sp@-		| save registers
870	movl	%usp,%a0		| and save
871	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
872	jbsr	_C_LABEL(nmintr)	| call handler: XXX wrapper
873	movl	%sp@(FR_SP),%a0		| restore
874	movl	%a0,%usp		|   user SP
875	moveml	%sp@+,#0x7FFF		| and remaining registers
876	addql	#8,%sp			| pop SP and stack adjust
877	rte
878#endif
879
880ENTRY_NOPROFILE(intrhand_vectored)
881	INTERRUPT_SAVEREG
882	lea	%sp@(16),%a1		| get pointer to frame
883	movl	%a1,%sp@-
884	movw	%sp@(26),%d0
885	movl	%d0,%sp@-		| push exception vector info
886	movl	%sp@(26),%sp@-		| and PC
887	jbsr	_C_LABEL(isrdispatch_vectored) | call dispatcher
888	lea	%sp@(12),%sp		| pop value args
889	INTERRUPT_RESTOREREG
890	rte
891
892#undef INTERRUPT_SAVEREG
893#undef INTERRUPT_RESTOREREG
894
895/*
896 * Emulation of VAX REI instruction.
897 *
898 * This code deals with checking for and servicing ASTs
899 * (profiling, scheduling) and software interrupts (network, softclock).
900 * We check for ASTs first, just like the VAX.  To avoid excess overhead
901 * the T_ASTFLT handling code will also check for software interrupts so we
902 * do not have to do it here.  After identifing that we need an AST we
903 * drop the IPL to allow device interrupts.
904 *
905 * This code is complicated by the fact that sendsig may have been called
906 * necessitating a stack cleanup.
907 */
908/*
909 * news68k has hardware support for AST and software interrupt.
910 * We just use it rather than VAX REI emulation.
911 */
912
913ASENTRY_NOPROFILE(rei)
914	tstl	_C_LABEL(astpending)	| AST pending?
915	jne	Lrei1			| no, done
916	rte
917Lrei1:
918	btst	#5,%sp@			| yes, are we returning to user mode?
919	jeq	1f			| no, done
920	rte
9211:
922	movw	#PSL_LOWIPL,%sr		| lower SPL
923	clrl	%sp@-			| stack adjust
924	moveml	#0xFFFF,%sp@-		| save all registers
925	movl	%usp,%a1		| including
926	movl	%a1,%sp@(FR_SP)		|    the users SP
927Lrei2:
928	clrl	%sp@-			| VA == none
929	clrl	%sp@-			| code == none
930	movl	#T_ASTFLT,%sp@-		| type == async system trap
931	jbsr	_C_LABEL(trap)		| go handle it
932	lea	%sp@(12),%sp		| pop value args
933	movl	%sp@(FR_SP),%a0		| restore user SP
934	movl	%a0,%usp		|   from save area
935	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
936	jne	Laststkadj		| yes, go to it
937	moveml	%sp@+,#0x7FFF		| no, restore most user regs
938	addql	#8,%sp			| toss SP and stack adjust
939	rte				| and do real RTE
940Laststkadj:
941	lea	%sp@(FR_HW),%a1		| pointer to HW frame
942	addql	#8,%a1			| source pointer
943	movl	%a1,%a0			| source
944	addw	%d0,%a0			|  + hole size = dest pointer
945	movl	%a1@-,%a0@-		| copy
946	movl	%a1@-,%a0@-		|  8 bytes
947	movl	%a0,%sp@(FR_SP)		| new SSP
948	moveml	%sp@+,#0x7FFF		| restore user registers
949	movl	%sp@,%sp		| and our SP
950	rte				| real return
951
952/*
953 * Use common m68k sigcode.
954 */
955#include <m68k/m68k/sigcode.s>
956#ifdef COMPAT_SUNOS
957#include <m68k/m68k/sunos_sigcode.s>
958#endif
959#ifdef COMPAT_SVR4
960#include <m68k/m68k/svr4_sigcode.s>
961#endif
962
963/*
964 * Primitives
965 */
966
967/*
968 * Use common m68k support routines.
969 */
970#include <m68k/m68k/support.s>
971
972/*
973 * Use common m68k process manipulation routines.
974 */
975#include <m68k/m68k/proc_subr.s>
976
977	.data
978GLOBAL(curpcb)
979GLOBAL(masterpaddr)		| XXXcompatibility (debuggers)
980	.long	0
981
982ASLOCAL(mdpflag)
983	.byte	0		| copy of proc md_flags low byte
984#ifdef __ELF__
985	.align	4
986#else
987	.align	2
988#endif
989
990ASBSS(nullpcb,SIZEOF_PCB)
991
992/*
993 * At exit of a process, do a switch for the last time.
994 * Switch to a safe stack and PCB, and select a new process to run.  The
995 * old stack and u-area will be freed by the reaper.
996 *
997 * MUST BE CALLED AT SPLHIGH!
998 */
999ENTRY(switch_exit)
1000	movl    %sp@(4),%a0
1001	/* save state into garbage pcb */
1002	movl    #_ASM_LABEL(nullpcb),_C_LABEL(curpcb)
1003	lea     _ASM_LABEL(tmpstk),%sp	| goto a tmp stack
1004
1005	/* Schedule the vmspace and stack to be freed. */
1006	movl	%a0,%sp@-		| exit2(p)
1007	jbsr	_C_LABEL(exit2)
1008	lea	%sp@(4),%sp	| pop args
1009
1010#if defined(LOCKDEBUG)
1011	/* Acquire sched_lock */
1012	jbsr	C_LABEL(sched_lock_idle)
1013#endif
1014
1015	jra	_C_LABEL(cpu_switch)
1016
1017/*
1018 * When no processes are on the runq, Swtch branches to Idle
1019 * to wait for something to come ready.
1020 */
1021ASENTRY_NOPROFILE(Idle)
1022#if defined(LOCKDEBUG)
1023	/* Release sched_lock */
1024	jbsr	_C_LABEL(sched_unlock_idle)
1025#endif
1026	movw	#PSL_LOWIPL,%sr
1027
1028	/* Try to zero some pages. */
1029	movl	_C_LABEL(uvm)+UVM_PAGE_IDLE_ZERO,%d0
1030	jeq	1f
1031	jbsr	_C_LABEL(uvm_pageidlezero)
1032	jra	2f
10331:
1034	stop	#PSL_LOWIPL
10352:
1036	movw	#PSL_HIGHIPL,%sr
1037#if defined(LOCKDEBUG)
1038	/* Acquire sched_lock */
1039	jbsr	_C_LABEL(sched_lock_idle)
1040#endif
1041	movl    _C_LABEL(sched_whichqs),%d0
1042	jeq     _ASM_LABEL(Idle)
1043	jra	Lsw1
1044
1045Lbadsw:
1046	PANIC("switch")
1047	/*NOTREACHED*/
1048
1049/*
1050 * cpu_switch()
1051 *
1052 * NOTE: On the mc68851 we attempt to avoid flushing the
1053 * entire ATC.  The effort involved in selective flushing may not be
1054 * worth it, maybe we should just flush the whole thing?
1055 *
1056 * NOTE 2: With the new VM layout we now no longer know if an inactive
1057 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1058 * bit).  For now, we just always flush the full ATC.
1059 */
1060ENTRY(cpu_switch)
1061	movl	_C_LABEL(curpcb),%a0	| current pcb
1062	movw	%sr,%a0@(PCB_PS)	| save sr before changing ipl
1063#ifdef notyet
1064	movl	_C_LABEL(curproc),%sp@-	| remember last proc running
1065#endif
1066	clrl	_C_LABEL(curproc)
1067
1068	/*
1069	 * Find the highest-priority queue that isn't empty,
1070	 * then take the first proc from that queue.
1071	 */
1072	movl    _C_LABEL(sched_whichqs),%d0
1073	jeq     _ASM_LABEL(Idle)
1074Lsw1:
1075	/*
1076	 * Interrupts are blocked, sched_lock is held.  If
1077	 * we come here via Idle, %d0 contains the contents
1078	 * of a non-zero sched_whichqs.
1079	 */
1080	movl    %d0,%d1
1081	negl    %d0
1082	andl    %d1,%d0
1083	bfffo   %d0{#0:#32},%d1
1084	eorib   #31,%d1
1085
1086	movl    %d1,%d0
1087	lslb    #3,%d1			| convert queue number to index
1088	addl    #_C_LABEL(sched_qs),%d1	| locate queue (q)
1089	movl    %d1,%a1
1090	movl    %a1@(P_FORW),%a0	| p = q->p_forw
1091	cmpal   %d1,%a0			| anyone on queue?
1092	jeq     Lbadsw                  | no, panic
1093#ifdef DIAGNOSTIC
1094	tstl	%a0@(P_WCHAN)
1095	jne	Lbadsw
1096	cmpb	#SRUN,%a0@(P_STAT)
1097	jne	Lbadsw
1098#endif
1099	movl    %a0@(P_FORW),%a1@(P_FORW) | q->p_forw = p->p_forw
1100	movl    %a0@(P_FORW),%a1	| n = p->p_forw
1101	movl    %d1,%a1@(P_BACK)	| n->p_back = q
1102	cmpal   %d1,%a1			| anyone left on queue?
1103	jne     Lsw2                    | yes, skip
1104	movl    _C_LABEL(sched_whichqs),%d1
1105	bclr    %d0,%d1			| no, clear bit
1106	movl    %d1,_C_LABEL(sched_whichqs)
1107Lsw2:
1108	/* p->p_cpu initialized in fork1() for single-processor */
1109	movb	#SONPROC,%a0@(P_STAT)	| p->p_stat = SONPROC
1110	movl	%a0,_C_LABEL(curproc)
1111	clrl	_C_LABEL(want_resched)
1112#ifdef notyet
1113	movl	%sp@+,%a1
1114	cmpl	%a0,%a1			| switching to same proc?
1115	jeq	Lswdone			| yes, skip save and restore
1116#endif
1117	/*
1118	 * Save state of previous process in its pcb.
1119	 */
1120	movl	_C_LABEL(curpcb),%a1
1121	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
1122	movl	%usp,%a2		| grab USP (a2 has been saved)
1123	movl	%a2,%a1@(PCB_USP)	| and save it
1124
1125	tstl	_C_LABEL(fputype)	| Do we have an FPU?
1126	jeq	Lswnofpsave		| No  Then don't attempt save.
1127	lea	%a1@(PCB_FPCTX),%a2	| pointer to FP save area
1128	fsave	%a2@			| save FP state
1129	tstb	%a2@			| null state frame?
1130	jeq	Lswnofpsave		| yes, all done
1131	fmovem	%fp0-%fp7,%a2@(FPF_REGS) | save FP general registers
1132	fmovem	%fpcr/%fpsr/%fpi,%a2@(FPF_FPCR) | save FP control registers
1133Lswnofpsave:
1134
1135	clrl	%a0@(P_BACK)		| clear back link
1136	/* low byte of p_md.md_flags */
1137	movb	%a0@(P_MD_FLAGS+3),_ASM_LABEL(mdpflag)
1138	movl	%a0@(P_ADDR),%a1		| get p_addr
1139	movl	%a1,_C_LABEL(curpcb)
1140
1141#if defined(LOCKDEBUG)
1142	/*
1143	 * Done mucking with the run queues, release the
1144	 * scheduler lock, but keep interrupts out.
1145	 */
1146	movl	%a0,sp@-		| not args...
1147	movl	%a1,sp@-		| ...just saving
1148	jbsr	_C_LABEL(sched_unlock_idle)
1149	movl	sp@+,%a1
1150	movl	sp@+,%a0
1151#endif
1152
1153	/*
1154	 * Activate process's address space.
1155	 * XXX Should remember the last USTP value loaded, and call this
1156	 * XXX only of it has changed.
1157	 */
1158	pea	%a0@			| push proc
1159	jbsr	_C_LABEL(pmap_activate)	| pmap_activate(p)
1160	addql	#4,%sp
1161	movl	_C_LABEL(curpcb),%a1	| restore p_addr
1162
1163	lea     _ASM_LABEL(tmpstk),%sp	| now goto a tmp stack for NMI
1164
1165	moveml	%a1@(PCB_REGS),#0xFCFC	| and registers
1166	movl	%a1@(PCB_USP),%a0
1167	movl	%a0,%usp		| and USP
1168
1169	tstl	_C_LABEL(fputype)	| If we don't have an FPU,
1170	jeq	Lnofprest		|  don't try to restore it.
1171	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
1172	tstb	%a0@			| null state frame?
1173	jeq	Lresfprest		| yes, easy
1174	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers
1175	fmovem	%a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers
1176Lresfprest:
1177	frestore %a0@			| restore state
1178Lnofprest:
1179	movw	%a1@(PCB_PS),%sr	| no, restore PS
1180	moveq	#1,%d0			| return 1 (for alternate returns)
1181	rts
1182
1183/*
1184 * savectx(pcb)
1185 * Update pcb, saving current processor state.
1186 */
1187ENTRY(savectx)
1188	movl	%sp@(4),%a1
1189	movw	%sr,%a1@(PCB_PS)
1190	movl	%usp,%a0		| grab USP
1191	movl	%a0,%a1@(PCB_USP)	| and save it
1192	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
1193
1194	tstl	_C_LABEL(fputype)	| Do we have FPU?
1195	jeq	Lsvnofpsave		| No?  Then don't save state.
1196	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
1197	fsave	%a0@			| save FP state
1198	tstb	%a0@			| null state frame?
1199	jeq	Lsvnofpsave		| yes, all done
1200	fmovem	%fp0-%fp7,%a0@(FPF_REGS) | save FP general registers
1201	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers
1202Lsvnofpsave:
1203	moveq	#0,%d0			| return 0
1204	rts
1205
1206ENTRY(ecacheon)
1207	tstl	_C_LABEL(ectype)
1208	jeq	Lnocache7
1209	movl	_C_LABEL(cache_ctl),%a0
1210	st	%a0@			| NEWS-OS does `st 0xe1300000'
1211Lnocache7:
1212	rts
1213
1214ENTRY(ecacheoff)
1215	tstl	_C_LABEL(ectype)
1216	jeq	Lnocache8
1217	movl	_C_LABEL(cache_ctl),%a0
1218	sf	%a0@			| NEWS-OS does `sf 0xe1300000'
1219Lnocache8:
1220	rts
1221
1222ENTRY_NOPROFILE(getsfc)
1223	movc	%sfc,%d0
1224	rts
1225
1226ENTRY_NOPROFILE(getdfc)
1227	movc	%dfc,%d0
1228	rts
1229
1230/*
1231 * Load a new user segment table pointer.
1232 */
1233ENTRY(loadustp)
1234	movl	%sp@(4),%d0		| new USTP
1235	moveq	#PGSHIFT, %d1
1236	lsll	%d1,%d0			| convert to addr
1237	pflusha				| flush entire TLB
1238	lea	_C_LABEL(protorp),%a0	| CRP prototype
1239	movl	%d0,%a0@(4)		| stash USTP
1240	pmove	%a0@,%crp		| load root pointer
1241	movc	%cacr,%d0
1242	orl	#DCIC_CLR,%d0
1243	movc	%d0,%cacr		| invalidate cache(s)
1244	rts
1245
1246ENTRY(ploadw)
1247	movl	%sp@(4),%a0		| address to load
1248	ploadw	#1,%a0@			| pre-load translation
1249	rts
1250
1251ENTRY(getsr)
1252	moveq	#0,%d0
1253	movw	%sr,%d0
1254	rts
1255
1256/*
1257 * _delay(unsigned N)
1258 *
1259 * Delay for at least (N/256) microseconds.
1260 * This routine depends on the variable:  delay_divisor
1261 * which should be set based on the CPU clock rate.
1262 */
1263ENTRY_NOPROFILE(_delay)
1264	| %d0 = arg = (usecs << 8)
1265	movl	%sp@(4),%d0
1266	| %d1 = delay_divisor
1267	movl	_C_LABEL(delay_divisor),%d1
1268	jra	L_delay			/* Jump into the loop! */
1269
1270	/*
1271	 * Align the branch target of the loop to a half-line (8-byte)
1272	 * boundary to minimize cache effects.  This guarantees both
1273	 * that there will be no prefetch stalls due to cache line burst
1274	 * operations and that the loop will run from a single cache
1275	 * half-line.
1276	 */
1277#ifdef __ELF__
1278	.align  8
1279#else
1280	.align	3
1281#endif
1282L_delay:
1283	subl	%d1,%d0
1284	jgt	L_delay
1285	rts
1286
1287/*
1288 * Save and restore 68881 state.
1289 */
1290ENTRY(m68881_save)
1291	movl	%sp@(4),%a0		| save area pointer
1292	fsave	%a0@			| save state
1293Lm68881fpsave:
1294	tstb	%a0@			| null state frame?
1295	jeq	Lm68881sdone		| yes, all done
1296	fmovem	%fp0-%fp7,%a0@(FPF_REGS) | save FP general registers
1297	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers
1298Lm68881sdone:
1299	rts
1300
1301ENTRY(m68881_restore)
1302	movl	%sp@(4),%a0		| save area pointer
1303Lm68881fprestore:
1304	tstb	%a0@			| null state frame?
1305	jeq	Lm68881rdone		| yes, easy
1306	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers
1307	fmovem	%a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers
1308Lm68881rdone:
1309	frestore %a0@			| restore state
1310	rts
1311
1312/*
1313 * Handle the nitty-gritty of rebooting the machine.
1314 * Basically we just turn off the MMU, restore the PROM's initial VBR
1315 * and jump through the PROM halt vector with argument via %d7
1316 * depending on how the system was halted.
1317 */
1318ENTRY_NOPROFILE(doboot)
1319#if defined(M68040)
1320	cmpl	#MMU_68040,_C_LABEL(mmutype)	| 68040?
1321	jeq	Lnocache5		| yes, skip
1322#endif
1323	movl	#CACHE_OFF,%d0
1324	movc	%d0,%cacr		| disable on-chip cache(s)
1325Lnocache5:
1326	movl	_C_LABEL(boothowto),%d7	| load howto
1327	movl	_C_LABEL(bootdev),%d6	| load bootdev
1328	movl	%sp@(4),%d2		| arg
1329	movl	_C_LABEL(ctrl_power),%a0| CTRL_POWER port
1330	movl	_ASM_LABEL(monitor_vbr),%d3	| Fetch original VBR value
1331	lea	_ASM_LABEL(tmpstk),%sp	| physical SP in case of NMI
1332	movl	#0,%a7@-		| value for pmove to TC (turn off MMU)
1333	pmove	%a7@,%tc		| disable MMU
1334	movc	%d3,%vbr		| Restore monitor's VBR
1335	movl	%d2,%d0			|
1336	andl	#0x800,%d0		| mask off
1337	tstl	%d0			| power down?
1338	beq	1f			|
1339	clrb	%a0@			| clear CTRL_POWER port
13401:
1341	tstl	%d2			| autoboot?
1342	beq	2f			| yes!
1343	movl	%d2,%d7			|
13442:
1345	trap	#15
1346	/* NOTREACHED */
1347
1348ASENTRY_NOPROFILE(debug_led)
1349	lea	0xe0dc0000,%a0
1350	movl	%d0,%a0@
1351
13521:	nop
1353	jmp	1b
1354	rts
1355
1356ASENTRY_NOPROFILE(debug_led2)
1357	movl	_C_LABEL(intiobase),%d1
1358	addl    #(0xe0dc0000-INTIOBASE1700),%d1
1359	movl    %d1,%a0
1360	movl	%d0,%a0@
1361
13621:	nop
1363	jmp	1b
1364	rts
1365
1366
1367/*
1368 * Misc. global variables.
1369 */
1370	.data
1371
1372GLOBAL(systype)
1373	.long	NEWS1700	| default to NEWS1700
1374
1375GLOBAL(mmutype)
1376	.long	MMU_68030	| default to MMU_68030
1377
1378GLOBAL(cputype)
1379	.long	CPU_68030	| default to CPU_68030
1380
1381GLOBAL(fputype)
1382	.long	FPU_68882	| default to FPU_68882
1383
1384GLOBAL(ectype)
1385	.long	EC_NONE		| external cache type, default to none
1386
1387GLOBAL(protorp)
1388	.long	0,0		| prototype root pointer
1389
1390GLOBAL(prototc)
1391	.long	0		| prototype translation control
1392
1393GLOBAL(protott0)
1394	.long	0		| prototype transparent translation register 0
1395
1396GLOBAL(protott1)
1397	.long	0		| prototype transparent translation register 1
1398
1399/*
1400 * Information from first stage boot program
1401 */
1402GLOBAL(bootpart)
1403	.long	0
1404GLOBAL(bootdevlun)
1405	.long	0
1406GLOBAL(bootctrllun)
1407	.long	0
1408GLOBAL(bootaddr)
1409	.long	0
1410
1411GLOBAL(want_resched)
1412	.long	0
1413
1414GLOBAL(proc0paddr)
1415	.long	0		| KVA of proc0 u-area
1416
1417GLOBAL(intiobase)
1418	.long	0		| KVA of base of internal IO space
1419
1420GLOBAL(extiobase)
1421	.long	0		| KVA of base of internal IO space
1422
1423GLOBAL(intiolimit)
1424	.long	0		| KVA of end of internal IO space
1425
1426GLOBAL(intiobase_phys)
1427	.long	0		| PA of board's I/O registers
1428
1429GLOBAL(intiotop_phys)
1430	.long	0		| PA of top of board's I/O registers
1431
1432GLOBAL(extiobase_phys)
1433	.long	0		| PA of external I/O registers
1434
1435GLOBAL(extiotop_phys)
1436	.long	0		| PA of top of external I/O registers
1437
1438GLOBAL(ctrl_power)
1439	.long	0		| PA of power control port
1440
1441GLOBAL(cache_ctl)
1442	.long	0		| KVA of external cache control port
1443
1444GLOBAL(cache_clr)
1445	.long	0		| KVA of external cache clear port
1446
1447
1448/* interrupt counters */
1449GLOBAL(intrnames)
1450	.asciz	"spur"
1451	.asciz	"AST"		| lev1: AST
1452	.asciz	"softint"	| lev2: software interrupt
1453	.asciz	"lev3"		| lev3: slot intr, VME intr 2, fd, lpt
1454	.asciz	"lev4"		| lev4: slot intr, VME intr 4, le, scsi
1455	.asciz	"lev5"		| lev5: kb, ms, zs
1456	.asciz	"clock"		| lev6: clock
1457	.asciz	"nmi"		| parity error
1458GLOBAL(eintrnames)
1459	.even
1460
1461GLOBAL(intrcnt)
1462	.long	0,0,0,0,0,0,0,0
1463GLOBAL(eintrcnt)
1464