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