xref: /netbsd/sys/arch/sun3/sun3x/locore.s (revision c4a72b64)
1/*	$NetBSD: locore.s,v 1.50 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 *	@(#)locore.s	8.6 (Berkeley) 5/27/94
42 */
43
44#include "opt_compat_netbsd.h"
45#include "opt_compat_svr4.h"
46#include "opt_compat_sunos.h"
47#include "opt_kgdb.h"
48#include "opt_lockdebug.h"
49
50#include "assym.h"
51#include <machine/asm.h>
52#include <machine/trap.h>
53
54| Remember this is a fun project!
55
56	.data
57GLOBAL(mon_crp)
58	.long	0,0
59
60| This is for kvm_mkdb, and should be the address of the beginning
61| of the kernel text segment (not necessarily the same as kernbase).
62	.text
63GLOBAL(kernel_text)
64
65| This is the entry point, as well as the end of the temporary stack
66| used during process switch (one 8K page ending at start)
67ASGLOBAL(tmpstk)
68ASGLOBAL(start)
69
70| The first step, after disabling interrupts, is to map enough of the kernel
71| into high virtual address space so that we can use position dependent code.
72| This is a tricky task on the sun3x because the MMU is already enabled and
73| the ROM monitor provides no indication of where the root MMU table is mapped.
74| Therefore we must use one of the 68030's 'transparent translation' registers
75| to define a range in the address space where the MMU translation is
76| turned off.  Once this is complete we can modify the MMU table directly
77| without the need for it to be mapped into virtual memory.
78| All code must be position independent until otherwise noted, as the
79| boot loader has loaded us into low memory but all the symbols in this
80| code have been linked high.
81	movw	#PSL_HIGHIPL,%sr	| no interrupts
82	movl	#KERNBASE,%a5		| for vtop conversion
83	lea	_C_LABEL(mon_crp),%a0	| where to store the CRP
84	subl	%a5,%a0
85	| Note: borrowing mon_crp for tt0 setup...
86	movl	#0x3F8107,%a0@		| map the low 1GB v=p with the
87	.long	0xf0100800		| transparent translation reg0
88					| [ pmove a0@, tt0 ]
89| In order to map the kernel into high memory we will copy the root table
90| entry which maps the 16 megabytes of memory starting at 0x0 into the
91| entry which maps the 16 megabytes starting at KERNBASE.
92	pmove	%crp,%a0@		| Get monitor CPU root pointer
93	movl	%a0@(4),%a1		| 2nd word is PA of level A table
94
95	movl	%a1,%a0			| compute the descriptor address
96	addl	#0x3e0,%a1		| for VA starting at KERNBASE
97	movl	%a0@,%a1@		| copy descriptor type
98	movl	%a0@(4),%a1@(4)		| copy physical address
99
100| Kernel is now double mapped at zero and KERNBASE.
101| Force a long jump to the relocated code (high VA).
102	movl	#IC_CLEAR,%d0		| Flush the I-cache
103	movc	%d0,%cacr
104	jmp L_high_code:l		| long jump
105
106L_high_code:
107| We are now running in the correctly relocated kernel, so
108| we are no longer restricted to position-independent code.
109| It is handy to leave transparent translation enabled while
110| for the low 1GB while _bootstrap() is doing its thing.
111
112| Do bootstrap stuff needed before main() gets called.
113| Our boot loader leaves a copy of the kernel's exec header
114| just before the start of the kernel text segment, so the
115| kernel can sanity-check the DDB symbols at [end...esym].
116| Pass the struct exec at tmpstk-32 to _bootstrap().
117| Also, make sure the initial frame pointer is zero so that
118| the backtrace algorithm used by KGDB terminates nicely.
119	lea	_ASM_LABEL(tmpstk)-32,%sp
120	movl	#0,%a6
121	jsr	_C_LABEL(_bootstrap)	| See locore2.c
122
123| Now turn off the transparent translation of the low 1GB.
124| (this also flushes the ATC)
125	clrl	%sp@-
126	.long	0xf0170800		| pmove	sp@,tt0
127	addql	#4,%sp
128
129| Now that _bootstrap() is done using the PROM functions,
130| we can safely set the sfc/dfc to something != FC_CONTROL
131	moveq	#FC_USERD,%d0		| make movs access "user data"
132	movc	%d0,%sfc		| space for copyin/copyout
133	movc	%d0,%dfc
134
135| Setup process zero user/kernel stacks.
136	movl	_C_LABEL(proc0paddr),%a1| get proc0 pcb addr
137	lea	%a1@(USPACE-4),%sp	| set SSP to last word
138	movl	#USRSTACK-4,%a2
139	movl	%a2,%usp		| init user SP
140
141| Note curpcb was already set in _bootstrap().
142| Will do fpu initialization during autoconfig (see fpu.c)
143| The interrupt vector table and stack are now ready.
144| Interrupts will be enabled later, AFTER  autoconfiguration
145| is finished, to avoid spurrious interrupts.
146
147/*
148 * Create a fake exception frame so that cpu_fork() can copy it.
149 * main() nevers returns; we exit to user mode from a forked process
150 * later on.
151 */
152	clrw	%sp@-			| tf_format,tf_vector
153	clrl	%sp@-			| tf_pc (filled in later)
154	movw	#PSL_USER,%sp@-		| tf_sr for user mode
155	clrl	%sp@-			| tf_stackadj
156	lea	%sp@(-64),%sp		| tf_regs[16]
157	lea	_C_LABEL(proc0),%a0	| proc0.p_md.md_regs =
158	movl	%a1,%a0@(P_MDREGS)	|   trapframe
159	jbsr	_C_LABEL(main)		| main(&trapframe)
160	PANIC("main() returned")
161
162/*
163 * proc_trampoline: call function in register %a2 with %a3 as an arg
164 * and then rei.
165 */
166GLOBAL(proc_trampoline)
167	movl	%a3,%sp@-		| push function arg
168	jbsr	%a2@			| call function
169	addql	#4,%sp			| pop arg
170	movl	%sp@(FR_SP),%a0		| grab and load
171	movl	%a0,%usp		|   user SP
172	moveml	%sp@+,#0x7FFF		| restore most user regs
173	addql	#8,%sp			| toss SP and stack adjust
174	jra	_ASM_LABEL(rei)		| and return
175
176| That is all the assembly startup code we need on the sun3x!
177| The rest of this is like the hp300/locore.s where possible.
178
179/*
180 * Trap/interrupt vector routines
181 */
182#include <m68k/m68k/trap_subr.s>
183
184GLOBAL(buserr)
185	tstl	_C_LABEL(nofault)	| device probe?
186	jeq	_C_LABEL(addrerr)	| no, handle as usual
187	movl	_C_LABEL(nofault),%sp@-	| yes,
188	jbsr	_C_LABEL(longjmp)	|  longjmp(nofault)
189GLOBAL(addrerr)
190	clrl	%sp@-			| stack adjust count
191	moveml	#0xFFFF,%sp@-		| save user registers
192	movl	%usp,%a0		| save the user SP
193	movl	%a0,%sp@(FR_SP)		|   in the savearea
194	lea	%sp@(FR_HW),%a1		| grab base of HW berr frame
195	moveq	#0,%d0
196	movw	%a1@(10),%d0		| grab SSW for fault processing
197	btst	#12,%d0			| RB set?
198	jeq	LbeX0			| no, test RC
199	bset	#14,%d0			| yes, must set FB
200	movw	%d0,%a1@(10)		| for hardware too
201LbeX0:
202	btst	#13,%d0			| RC set?
203	jeq	LbeX1			| no, skip
204	bset	#15,%d0			| yes, must set FC
205	movw	%d0,%a1@(10)		| for hardware too
206LbeX1:
207	btst	#8,%d0			| data fault?
208	jeq	Lbe0			| no, check for hard cases
209	movl	%a1@(16),%d1		| fault address is as given in frame
210	jra	Lbe10			| thats it
211Lbe0:
212	btst	#4,%a1@(6)		| long (type B) stack frame?
213	jne	Lbe4			| yes, go handle
214	movl	%a1@(2),%d1		| no, can use save PC
215	btst	#14,%d0			| FB set?
216	jeq	Lbe3			| no, try FC
217	addql	#4,%d1			| yes, adjust address
218	jra	Lbe10			| done
219Lbe3:
220	btst	#15,%d0			| FC set?
221	jeq	Lbe10			| no, done
222	addql	#2,%d1			| yes, adjust address
223	jra	Lbe10			| done
224Lbe4:
225	movl	%a1@(36),%d1		| long format, use stage B address
226	btst	#15,%d0			| FC set?
227	jeq	Lbe10			| no, all done
228	subql	#2,%d1			| yes, adjust address
229Lbe10:
230	movl	%d1,%sp@-		| push fault VA
231	movl	%d0,%sp@-		| and padded SSW
232	movw	%a1@(6),%d0		| get frame format/vector offset
233	andw	#0x0FFF,%d0		| clear out frame format
234	cmpw	#12,%d0			| address error vector?
235	jeq	Lisaerr			| yes, go to it
236
237/* MMU-specific code to determine reason for bus error. */
238	movl	%d1,%a0			| fault address
239	movl	%sp@,%d0		| function code from ssw
240	btst	#8,%d0			| data fault?
241	jne	Lbe10a
242	movql	#1,%d0			| user program access FC
243					| (we dont separate data/program)
244	btst	#5,%a1@			| supervisor mode?
245	jeq	Lbe10a			| if no, done
246	movql	#5,%d0			| else supervisor program access
247Lbe10a:
248	ptestr	%d0,%a0@,#7		| do a table search
249	pmove	%psr,%sp@		| save result
250	movb	%sp@,%d1
251	btst	#2,%d1			| invalid? (incl. limit viol and berr)
252	jeq	Lmightnotbemerr		| no -> wp check
253	btst	#7,%d1			| is it MMU table berr?
254	jeq	Lismerr			| no, must be fast
255	jra	Lisberr1		| real bus err needs not be fast
256Lmightnotbemerr:
257	btst	#3,%d1			| write protect bit set?
258	jeq	Lisberr1		| no, must be bus error
259	movl	%sp@,%d0		| ssw into low word of d0
260	andw	#0xc0,%d0		| write protect is set on page:
261	cmpw	#0x40,%d0		| was it read cycle?
262	jeq	Lisberr1		| yes, was not WPE, must be bus err
263/* End of MMU-specific bus error code. */
264
265Lismerr:
266	movl	#T_MMUFLT,%sp@-		| show that we are an MMU fault
267	jra	_ASM_LABEL(faultstkadj)	| and deal with it
268Lisaerr:
269	movl	#T_ADDRERR,%sp@-	| mark address error
270	jra	_ASM_LABEL(faultstkadj)	| and deal with it
271Lisberr1:
272	clrw	%sp@			| re-clear pad word
273Lisberr:
274	movl	#T_BUSERR,%sp@-		| mark bus error
275	jra	_ASM_LABEL(faultstkadj)	| and deal with it
276
277/*
278 * FP exceptions.
279 */
280GLOBAL(fpfline)
281	clrl	%sp@-			| stack adjust count
282	moveml	#0xFFFF,%sp@-		| save registers
283	moveq	#T_FPEMULI,%d0		| denote as FP emulation trap
284	jra	_ASM_LABEL(fault)	| do it
285
286GLOBAL(fpunsupp)
287	clrl	%sp@-			| stack adjust count
288	moveml	#0xFFFF,%sp@-		| save registers
289	moveq	#T_FPEMULD,%d0		| denote as FP emulation trap
290	jra	_ASM_LABEL(fault)	| do it
291
292/*
293 * Handles all other FP coprocessor exceptions.
294 * Note that since some FP exceptions generate mid-instruction frames
295 * and may cause signal delivery, we need to test for stack adjustment
296 * after the trap call.
297 */
298GLOBAL(fpfault)
299	clrl	%sp@-		| stack adjust count
300	moveml	#0xFFFF,%sp@-	| save user registers
301	movl	%usp,%a0	| and save
302	movl	%a0,%sp@(FR_SP)	|   the user stack pointer
303	clrl	%sp@-		| no VA arg
304	movl	_C_LABEL(curpcb),%a0	| current pcb
305	lea	%a0@(PCB_FPCTX),%a0 | address of FP savearea
306	fsave	%a0@		| save state
307	tstb	%a0@		| null state frame?
308	jeq	Lfptnull	| yes, safe
309	clrw	%d0		| no, need to tweak BIU
310	movb	%a0@(1),%d0	| get frame size
311	bset	#3,%a0@(0,%d0:w) | set exc_pend bit of BIU
312Lfptnull:
313	fmovem	%fpsr,%sp@-	| push fpsr as code argument
314	frestore %a0@		| restore state
315	movl	#T_FPERR,%sp@-	| push type arg
316	jra	_ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
317
318/*
319 * Other exceptions only cause four and six word stack frame and require
320 * no post-trap stack adjustment.
321 */
322GLOBAL(badtrap)
323	clrl	%sp@-			| stack adjust count
324	moveml	#0xFFFF,%sp@-		| save std frame regs
325	jbsr	_C_LABEL(straytrap)	| report
326	moveml	%sp@+,#0xFFFF		| restore regs
327	addql	#4,%sp			| stack adjust count
328	jra	_ASM_LABEL(rei)		| all done
329
330/*
331 * Trap 0 is for system calls
332 */
333GLOBAL(trap0)
334	clrl	%sp@-			| stack adjust count
335	moveml	#0xFFFF,%sp@-		| save user registers
336	movl	%usp,%a0		| save the user SP
337	movl	%a0,%sp@(FR_SP)		|   in the savearea
338	movl	%d0,%sp@-		| push syscall number
339	jbsr	_C_LABEL(syscall)	| handle it
340	addql	#4,%sp			| pop syscall arg
341	movl	%sp@(FR_SP),%a0		| grab and restore
342	movl	%a0,%usp		|   user SP
343	moveml	%sp@+,#0x7FFF		| restore most registers
344	addql	#8,%sp			| pop SP and stack adjust
345	jra	_ASM_LABEL(rei)		| all done
346
347/*
348 * Trap 12 is the entry point for the cachectl "syscall"
349 *	cachectl(command, addr, length)
350 * command in d0, addr in a1, length in d1
351 */
352GLOBAL(trap12)
353	movl	_C_LABEL(curproc),%sp@-	| push curproc pointer
354	movl	%d1,%sp@-		| push length
355	movl	%a1,%sp@-		| push addr
356	movl	%d0,%sp@-		| push command
357	jbsr	_C_LABEL(cachectl1)	| do it
358	lea	%sp@(16),%sp		| pop args
359	jra	_ASM_LABEL(rei)		| all done
360
361/*
362 * Trace (single-step) trap.  Kernel-mode is special.
363 * User mode traps are simply passed on to trap().
364 */
365GLOBAL(trace)
366	clrl	%sp@-			| stack adjust count
367	moveml	#0xFFFF,%sp@-
368	moveq	#T_TRACE,%d0
369
370	| Check PSW and see what happen.
371	|   T=0 S=0	(should not happen)
372	|   T=1 S=0	trace trap from user mode
373	|   T=0 S=1	trace trap on a trap instruction
374	|   T=1 S=1	trace trap from system mode (kernel breakpoint)
375
376	movw	%sp@(FR_HW),%d1		| get PSW
377	notw	%d1			| XXX no support for T0 on 680[234]0
378	andw	#PSL_TS,%d1		| from system mode (T=1, S=1)?
379	jeq	_ASM_LABEL(kbrkpt)	|  yes, kernel brkpt
380	jra	_ASM_LABEL(fault)	| no, user-mode fault
381
382/*
383 * Trap 15 is used for:
384 *	- GDB breakpoints (in user programs)
385 *	- KGDB breakpoints (in the kernel)
386 *	- trace traps for SUN binaries (not fully supported yet)
387 * User mode traps are simply passed to trap().
388 */
389GLOBAL(trap15)
390	clrl	%sp@-			| stack adjust count
391	moveml	#0xFFFF,%sp@-
392	moveq	#T_TRAP15,%d0
393	btst	#5,%sp@(FR_HW)		| was supervisor mode?
394	jne	_ASM_LABEL(kbrkpt)	|  yes, kernel brkpt
395	jra	_ASM_LABEL(fault)	| no, user-mode fault
396
397ASLOCAL(kbrkpt)
398	| Kernel-mode breakpoint or trace trap. (%d0=trap_type)
399	| Save the system sp rather than the user sp.
400	movw	#PSL_HIGHIPL,%sr	| lock out interrupts
401	lea	%sp@(FR_SIZE),%a6	| Save stack pointer
402	movl	%a6,%sp@(FR_SP)		|  from before trap
403
404	| If we are not on tmpstk switch to it.
405	| (so debugger can change the stack pointer)
406	movl	%a6,%d1
407	cmpl	#_ASM_LABEL(tmpstk),%d1
408	jls	Lbrkpt2 		| already on tmpstk
409	| Copy frame to the temporary stack
410	movl	%sp,%a0			| %a0=src
411	lea	_ASM_LABEL(tmpstk)-96,%a1 | %a1=dst
412	movl	%a1,%sp			| sp=new frame
413	moveq	#FR_SIZE,%d1
414Lbrkpt1:
415	movl	%a0@+,%a1@+
416	subql	#4,%d1
417	bgt	Lbrkpt1
418
419Lbrkpt2:
420	| Call the trap handler for the kernel debugger.
421	| Do not call trap() to handle it, so that we can
422	| set breakpoints in trap() if we want.  We know
423	| the trap type is either T_TRACE or T_BREAKPOINT.
424	movl	%d0,%sp@-		| push trap type
425	jbsr	_C_LABEL(trap_kdebug)
426	addql	#4,%sp			| pop args
427
428	| The stack pointer may have been modified, or
429	| data below it modified (by kgdb push call),
430	| so push the hardware frame at the current sp
431	| before restoring registers and returning.
432	movl	%sp@(FR_SP),%a0		| modified sp
433	lea	%sp@(FR_SIZE),%a1	| end of our frame
434	movl	%a1@-,%a0@-		| copy 2 longs with
435	movl	%a1@-,%a0@-		| ... predecrement
436	movl	%a0,%sp@(FR_SP)		| sp = h/w frame
437	moveml	%sp@+,#0x7FFF		| restore all but sp
438	movl	%sp@,%sp		| ... and sp
439	rte				| all done
440
441/* Use common m68k sigreturn */
442#include <m68k/m68k/sigreturn.s>
443
444/*
445 * Interrupt handlers.  Most are auto-vectored,
446 * and hard-wired the same way on all sun3 models.
447 * Format in the stack is:
448 *   %d0,%d1,%a0,%a1, sr, pc, vo
449 */
450
451#define INTERRUPT_SAVEREG \
452	moveml	#0xC0C0,%sp@-
453
454#define INTERRUPT_RESTORE \
455	moveml	%sp@+,#0x0303
456
457/*
458 * This is the common auto-vector interrupt handler,
459 * for which the CPU provides the vector=0x18+level.
460 * These are installed in the interrupt vector table.
461 */
462#ifdef __ELF__
463	.align	4
464#else
465	.align	2
466#endif
467GLOBAL(_isr_autovec)
468	INTERRUPT_SAVEREG
469	jbsr	_C_LABEL(isr_autovec)
470	INTERRUPT_RESTORE
471	jra	_ASM_LABEL(rei)
472
473/* clock: see clock.c */
474#ifdef __ELF__
475	.align	4
476#else
477	.align	2
478#endif
479GLOBAL(_isr_clock)
480	INTERRUPT_SAVEREG
481	jbsr	_C_LABEL(clock_intr)
482	INTERRUPT_RESTORE
483	jra	_ASM_LABEL(rei)
484
485| Handler for all vectored interrupts (i.e. VME interrupts)
486#ifdef __ELF__
487	.align	4
488#else
489	.align	2
490#endif
491GLOBAL(_isr_vectored)
492	INTERRUPT_SAVEREG
493	jbsr	_C_LABEL(isr_vectored)
494	INTERRUPT_RESTORE
495	jra	_ASM_LABEL(rei)
496
497#undef	INTERRUPT_SAVEREG
498#undef	INTERRUPT_RESTORE
499
500/* interrupt counters (needed by vmstat) */
501GLOBAL(intrnames)
502	.asciz	"spur"	| 0
503	.asciz	"lev1"	| 1
504	.asciz	"lev2"	| 2
505	.asciz	"lev3"	| 3
506	.asciz	"lev4"	| 4
507	.asciz	"clock"	| 5
508	.asciz	"lev6"	| 6
509	.asciz	"nmi"	| 7
510GLOBAL(eintrnames)
511
512	.data
513	.even
514GLOBAL(intrcnt)
515	.long	0,0,0,0,0,0,0,0,0,0
516GLOBAL(eintrcnt)
517	.text
518
519/*
520 * Emulation of VAX REI instruction.
521 *
522 * This code is (mostly) un-altered from the hp300 code,
523 * except that sun machines do not need a simulated SIR
524 * because they have a real software interrupt register.
525 *
526 * This code deals with checking for and servicing ASTs
527 * (profiling, scheduling) and software interrupts (network, softclock).
528 * We check for ASTs first, just like the VAX.  To avoid excess overhead
529 * the T_ASTFLT handling code will also check for software interrupts so we
530 * do not have to do it here.  After identifying that we need an AST we
531 * drop the IPL to allow device interrupts.
532 *
533 * This code is complicated by the fact that sendsig may have been called
534 * necessitating a stack cleanup.
535 */
536
537ASGLOBAL(rei)
538#ifdef	DIAGNOSTIC
539	tstl	_C_LABEL(panicstr)	| have we paniced?
540	jne	Ldorte			| yes, do not make matters worse
541#endif
542	tstl	_C_LABEL(astpending)	| AST pending?
543	jeq	Ldorte			| no, done
544Lrei1:
545	btst	#5,%sp@			| yes, are we returning to user mode?
546	jne	Ldorte			| no, done
547	movw	#PSL_LOWIPL,%sr		| lower SPL
548	clrl	%sp@-			| stack adjust
549	moveml	#0xFFFF,%sp@-		| save all registers
550	movl	%usp,%a1		| including
551	movl	%a1,%sp@(FR_SP)		|    the users SP
552	clrl	%sp@-			| VA == none
553	clrl	%sp@-			| code == none
554	movl	#T_ASTFLT,%sp@-		| type == async system trap
555	jbsr	_C_LABEL(trap)		| go handle it
556	lea	%sp@(12),%sp		| pop value args
557	movl	%sp@(FR_SP),%a0		| restore user SP
558	movl	%a0,%usp		|   from save area
559	movw	%sp@(FR_ADJ),%d0	| need to adjust stack?
560	jne	Laststkadj		| yes, go to it
561	moveml	%sp@+,#0x7FFF		| no, restore most user regs
562	addql	#8,%sp			| toss SP and stack adjust
563	rte				| and do real RTE
564Laststkadj:
565	lea	%sp@(FR_HW),%a1		| pointer to HW frame
566	addql	#8,%a1			| source pointer
567	movl	%a1,%a0			| source
568	addw	%d0,%a0			|  + hole size = dest pointer
569	movl	%a1@-,%a0@-		| copy
570	movl	%a1@-,%a0@-		|  8 bytes
571	movl	%a0,%sp@(FR_SP)		| new SSP
572	moveml	%sp@+,#0x7FFF		| restore user registers
573	movl	%sp@,%sp		| and our SP
574Ldorte:
575	rte				| real return
576
577/*
578 * Initialization is at the beginning of this file, because the
579 * kernel entry point needs to be at zero for compatibility with
580 * the Sun boot loader.  This works on Sun machines because the
581 * interrupt vector table for reset is NOT at address zero.
582 * (The MMU has a "boot" bit that forces access to the PROM)
583 */
584
585/*
586 * Use common m68k sigcode.
587 */
588#include <m68k/m68k/sigcode.s>
589#ifdef COMPAT_SUNOS
590#include <m68k/m68k/sunos_sigcode.s>
591#endif
592#ifdef COMPAT_SVR4
593#include <m68k/m68k/svr4_sigcode.s>
594#endif
595
596	.text
597
598/*
599 * Primitives
600 */
601
602/*
603 * Use common m68k support routines.
604 */
605#include <m68k/m68k/support.s>
606
607BSS(want_resched,4)
608
609/*
610 * Use common m68k process manipulation routines.
611 */
612#include <m68k/m68k/proc_subr.s>
613
614| Message for Lbadsw panic
615Lsw0:
616	.asciz	"cpu_switch"
617	.even
618
619	.data
620GLOBAL(masterpaddr)		| XXX compatibility (debuggers)
621GLOBAL(curpcb)
622	.long	0
623ASBSS(nullpcb,SIZEOF_PCB)
624	.text
625
626/*
627 * At exit of a process, do a cpu_switch for the last time.
628 * Switch to a safe stack and PCB, and select a new process to run.  The
629 * old stack and u-area will be freed by the reaper.
630 *
631 * MUST BE CALLED AT SPLHIGH!
632 */
633ENTRY(switch_exit)
634	movl	%sp@(4),%a0		| struct proc *p
635					| save state into garbage pcb
636	movl	#_ASM_LABEL(nullpcb),_C_LABEL(curpcb)
637	lea	_ASM_LABEL(tmpstk),%sp	| goto a tmp stack
638
639	/* Schedule the vmspace and stack to be freed. */
640	movl	%a0,%sp@-			| exit2(p)
641	jbsr	_C_LABEL(exit2)
642	lea	%sp@(4),%sp
643
644#if defined(LOCKDEBUG)
645	/* Acquire sched_lock */
646	jbsr	_C_LABEL(sched_lock_idle)
647#endif
648
649	jra	_C_LABEL(cpu_switch)
650
651/*
652 * When no processes are on the runq, cpu_switch() branches to idle
653 * to wait for something to come ready.
654 */
655Lidle:
656#if defined(LOCKDEBUG)
657	/* Release sched_lock */
658	jbsr	_C_LABEL(sched_unlock_idle)
659#endif
660	stop	#PSL_LOWIPL
661GLOBAL(_Idle)				| See clock.c
662	movw	#PSL_HIGHIPL,%sr
663#if defined(LOCKDEBUG)
664	/* Acquire sched_lock */
665	jbsr	_C_LABEL(sched_lock_idle)
666#endif
667	movl	_C_LABEL(sched_whichqs),%d0
668	jeq	Lidle
669	jra	Lsw1
670
671Lbadsw:
672	movl	#Lsw0,%sp@-
673	jbsr	_C_LABEL(panic)
674	/*NOTREACHED*/
675
676/*
677 * cpu_switch()
678 * Hacked for sun3
679 */
680ENTRY(cpu_switch)
681	movl	_C_LABEL(curpcb),%a1	| current pcb
682	movw	%sr,%a1@(PCB_PS)	| save sr before changing ipl
683#ifdef notyet
684	movl	_C_LABEL(curproc),%sp@-	| remember last proc running
685#endif
686	clrl	_C_LABEL(curproc)
687
688	/*
689	 * Find the highest-priority queue that isn't empty,
690	 * then take the first proc from that queue.
691	 */
692	movl	_C_LABEL(sched_whichqs),%d0
693	jeq	Lidle
694Lsw1:
695	/*
696	 * Interrupts are blocked, sched_lock is held.  If
697	 * we come here via Idle, %d0 contains the contents
698	 * of a non-zero sched_whichqs.
699	 */
700	movl	%d0,%d1
701	negl	%d0
702	andl	%d1,%d0
703	bfffo	%d0{#0:#32},%d1
704	eorib	#31,%d1
705
706	movl	%d1,%d0
707	lslb	#3,%d1			| convert queue number to index
708	addl	#_C_LABEL(sched_qs),%d1	| locate queue (q)
709	movl	%d1,%a1
710	movl	%a1@(P_FORW),%a0	| p = q->p_forw
711	cmpal	%d1,%a0			| anyone on queue?
712	jeq	Lbadsw			| no, panic
713#ifdef DIAGNOSTIC
714	tstl	%a0@(P_WCHAN)
715	jne	Lbadsw
716	cmpb	#SRUN,%a0@(P_STAT)
717	jne	Lbadsw
718#endif
719	movl	%a0@(P_FORW),%a1@(P_FORW)	| q->p_forw = p->p_forw
720	movl	%a0@(P_FORW),%a1		| n = p->p_forw
721	movl	%a0@(P_BACK),%a1@(P_BACK)	| n->p_back = q
722	cmpal	%d1,%a1			| anyone left on queue?
723	jne	Lsw2			| yes, skip
724	movl	_C_LABEL(sched_whichqs),%d1
725	bclr	%d0,%d1			| no, clear bit
726	movl	%d1,_C_LABEL(sched_whichqs)
727Lsw2:
728	/* p->p_cpu initialized in fork1() for single-processor */
729	movb	#SONPROC,%a0@(P_STAT)	| p->p_stat = SONPROC
730	movl	%a0,_C_LABEL(curproc)
731	clrl	_C_LABEL(want_resched)
732#ifdef notyet
733	movl	%sp@+,%a1		| XXX - Make this work!
734	cmpl	%a0,%a1			| switching to same proc?
735	jeq	Lswdone			| yes, skip save and restore
736#endif
737	/*
738	 * Save state of previous process in its pcb.
739	 */
740	movl	_C_LABEL(curpcb),%a1
741	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
742	movl	%usp,%a2		| grab USP (a2 has been saved)
743	movl	%a2,%a1@(PCB_USP)	| and save it
744
745	tstl	_C_LABEL(fputype)	| Do we have an fpu?
746	jeq	Lswnofpsave		| No?  Then don't try save.
747	lea	%a1@(PCB_FPCTX),%a2	| pointer to FP save area
748	fsave	%a2@			| save FP state
749	tstb	%a2@			| null state frame?
750	jeq	Lswnofpsave		| yes, all done
751	fmovem	%fp0-%fp7,%a2@(FPF_REGS)	| save FP general regs
752	fmovem	%fpcr/%fpsr/%fpi,%a2@(FPF_FPCR)	| save FP control regs
753Lswnofpsave:
754
755	/*
756	 * Now that we have saved all the registers that must be
757	 * preserved, we are free to use those registers until
758	 * we load the registers for the switched-to process.
759	 * In this section, keep:  %a0=curproc, %a1=curpcb
760	 */
761
762	clrl	%a0@(P_BACK)		| clear back link
763	movl	%a0@(P_ADDR),%a1		| get p_addr
764	movl	%a1,_C_LABEL(curpcb)
765
766#if defined(LOCKDEBUG)
767	/*
768	 * Done mucking with the run queues, release the
769	 * scheduler lock, but keep interrupts out.
770	 */
771	movl	%a0,%sp@-		| not args...
772	movl	%a1,%sp@-		| ...just saving
773	jbsr	_C_LABEL(sched_unlock_idle)
774	movl	%sp@+,%a1
775	movl	%sp@+,%a0
776#endif
777
778	/*
779	 * Load the new VM context (new MMU root pointer)
780	 */
781	movl	%a0@(P_VMSPACE),%a2	| vm = p->p_vmspace
782#ifdef DIAGNOSTIC
783	tstl	%a2			| vm == VM_MAP_NULL?
784	jeq	Lbadsw			| panic
785#endif
786#ifdef PMAP_DEBUG
787	/* When debugging just call _pmap_switch(). */
788	movl	%a2@(VM_PMAP),a2 	| pmap = vm->vm_map.pmap
789	pea	%a2@			| push pmap
790	jbsr	_C_LABEL(_pmap_switch)	| _pmap_switch(pmap)
791	addql	#4,%sp
792	movl	_C_LABEL(curpcb),%a1	| restore p_addr
793#else
794	/* Otherwise, use this inline version. */
795	lea	_C_LABEL(kernel_crp),%a3 | our CPU Root Ptr. (CRP)
796	movl	%a2@(VM_PMAP),%a2 	| pmap = vm->vm_map.pmap
797	movl	%a2@(PM_A_PHYS),%d0	| phys = pmap->pm_a_phys
798	cmpl	%a3@(4),%d0		|  == kernel_crp.rp_addr ?
799	jeq	Lsame_mmuctx		| skip loadcrp/flush
800	/* OK, it is a new MMU context.  Load it up. */
801	movl	%d0,%a3@(4)
802	movl	#CACHE_CLR,%d0
803	movc	%d0,%cacr		| invalidate cache(s)
804	pflusha				| flush entire TLB
805	pmove	%a3@,%crp		| load new user root pointer
806Lsame_mmuctx:
807#endif
808
809	/*
810	 * Reload the registers for the new process.
811	 * After this point we can only use %d0,%d1,%a0,%a1
812	 */
813	moveml	%a1@(PCB_REGS),#0xFCFC	| reload registers
814	movl	%a1@(PCB_USP),%a0
815	movl	%a0,%usp		| and USP
816
817	tstl	_C_LABEL(fputype)	| If we don't have an fpu,
818	jeq	Lres_skip		|  don't try to restore it.
819	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
820	tstb	%a0@			| null state frame?
821	jeq	Lresfprest		| yes, easy
822	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi	| restore FP control regs
823	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general regs
824Lresfprest:
825	frestore %a0@			| restore state
826Lres_skip:
827	movw	%a1@(PCB_PS),%d0		| no, restore PS
828#ifdef DIAGNOSTIC
829	btst	#13,%d0			| supervisor mode?
830	jeq	Lbadsw			| no? panic!
831#endif
832	movw	%d0,%sr			| OK, restore PS
833	movl	#1,%a0			| return 1 (for alternate returns)
834	rts
835
836/*
837 * savectx(pcb)
838 * Update pcb, saving current processor state.
839 */
840ENTRY(savectx)
841	movl	%sp@(4),%a1
842	movw	%sr,%a1@(PCB_PS)
843	movl	%usp,%a0		| grab USP
844	movl	%a0,%a1@(PCB_USP)	| and save it
845	moveml	#0xFCFC,%a1@(PCB_REGS)	| save non-scratch registers
846
847	tstl	_C_LABEL(fputype)	| Do we have FPU?
848	jeq	Lsavedone		| No?  Then don't save state.
849	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
850	fsave	%a0@			| save FP state
851	tstb	%a0@			| null state frame?
852	jeq	Lsavedone		| yes, all done
853	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general regs
854	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR)	| save FP control regs
855Lsavedone:
856	movl	#0,%a0			| return 0
857	rts
858
859/* suline() */
860
861#ifdef DEBUG
862	.data
863ASGLOBAL(fulltflush)
864	.long	0
865ASGLOBAL(fullcflush)
866	.long	0
867	.text
868#endif
869
870ENTRY(ecacheon)
871	rts
872
873ENTRY(ecacheoff)
874	rts
875
876/*
877 * Get callers current SP value.
878 * Note that simply taking the address of a local variable in a C function
879 * doesn't work because callee saved registers may be outside the stack frame
880 * defined by A6 (e.g. GCC generated code).
881 *
882 * [I don't think the ENTRY() macro will do the right thing with this -- glass]
883 */
884GLOBAL(getsp)
885	movl	%sp,%d0			| get current SP
886	addql	#4,%d0			| compensate for return address
887	movl	%d0,%a0
888	rts
889
890ENTRY(getsfc)
891	movc	%sfc,%d0
892	movl	%d0,%a0
893	rts
894
895ENTRY(getdfc)
896	movc	%dfc,%d0
897	movl	%d0,%a0
898	rts
899
900ENTRY(getvbr)
901	movc	%vbr,%d0
902	movl	%d0,%a0
903	rts
904
905ENTRY(setvbr)
906	movl	%sp@(4),%d0
907	movc	%d0,%vbr
908	rts
909
910/*
911 * Load a new CPU Root Pointer (CRP) into the MMU.
912 *	void	loadcrp(struct mmu_rootptr *);
913 */
914ENTRY(loadcrp)
915	movl	%sp@(4),%a0		| arg1: &CRP
916	movl	#CACHE_CLR,%d0
917	movc	%d0,%cacr		| invalidate cache(s)
918	pflusha				| flush entire TLB
919	pmove	%a0@,%crp		| load new user root pointer
920	rts
921
922ENTRY(getcrp)
923	movl	%sp@(4),%a0		| arg1: &crp
924	pmove	%crp,%a0@		| *crpp = %crp
925	rts
926
927/*
928 * Get the physical address of the PTE for a given VA.
929 */
930ENTRY(ptest_addr)
931	movl	%sp@(4),%a1		| VA
932	ptestr	#5,%a1@,#7,%a0		| %a0 = addr of PTE
933	movl	%a0,%d0			| Result in %d0 (not a pointer return)
934	rts
935
936/*
937 * Set processor priority level calls.  Most are implemented with
938 * inline asm expansions.  However, we need one instantiation here
939 * in case some non-optimized code makes external references.
940 * Most places will use the inlined functions param.h supplies.
941 */
942
943ENTRY(_getsr)
944	clrl	%d0
945	movw	%sr,%d0
946	movl	%a1,%d0
947	rts
948
949ENTRY(_spl)
950	clrl	%d0
951	movw	%sr,%d0
952	movl	%sp@(4),%d1
953	movw	%d1,%sr
954	rts
955
956ENTRY(_splraise)
957	clrl	%d0
958	movw	%sr,%d0
959	movl	%d0,%d1
960	andl	#PSL_HIGHIPL,%d1 	| old &= PSL_HIGHIPL
961	cmpl	%sp@(4),%d1		| (old - new)
962	bge	Lsplr
963	movl	%sp@(4),%d1
964	movw	%d1,%sr
965Lsplr:
966	rts
967
968/*
969 * Save and restore 68881 state.
970 */
971ENTRY(m68881_save)
972	movl	%sp@(4),%a0		| save area pointer
973	fsave	%a0@			| save state
974	tstb	%a0@			| null state frame?
975	jeq	Lm68881sdone		| yes, all done
976	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general regs
977	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR)	| save FP control regs
978Lm68881sdone:
979	rts
980
981ENTRY(m68881_restore)
982	movl	%sp@(4),%a0		| save area pointer
983	tstb	%a0@			| null state frame?
984	jeq	Lm68881rdone		| yes, easy
985	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi	| restore FP control regs
986	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general regs
987Lm68881rdone:
988	frestore %a0@			| restore state
989	rts
990
991/*
992 * _delay(unsigned N)
993 * Delay for at least (N/256) microseconds.
994 * This routine depends on the variable:  delay_divisor
995 * which should be set based on the CPU clock rate.
996 * XXX: Currently this is set based on the CPU model,
997 * XXX: but this should be determined at run time...
998 */
999GLOBAL(_delay)
1000	| %d0 = arg = (usecs << 8)
1001	movl	%sp@(4),%d0
1002	| %d1 = delay_divisor;
1003	movl	_C_LABEL(delay_divisor),%d1
1004	jra	L_delay			/* Jump into the loop! */
1005
1006	/*
1007	 * Align the branch target of the loop to a half-line (8-byte)
1008	 * boundary to minimize cache effects.  This guarantees both
1009	 * that there will be no prefetch stalls due to cache line burst
1010	 * operations and that the loop will run from a single cache
1011	 * half-line.
1012	 */
1013#ifdef __ELF__
1014	.align	8
1015#else
1016	.align	3
1017#endif
1018L_delay:
1019	subl	%d1,%d0
1020	jgt	L_delay
1021	rts
1022
1023| Define some addresses, mostly so DDB can print useful info.
1024| Not using _C_LABEL() here because these symbols are never
1025| referenced by any C code, and if the leading underscore
1026| ever goes away, these lines turn into syntax errors...
1027	.set	_KERNBASE,KERNBASE
1028	.set	_MONSTART,SUN3X_MONSTART
1029	.set	_PROM_BASE,SUN3X_PROM_BASE
1030	.set	_MONEND,SUN3X_MONEND
1031
1032|The end!
1033