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