xref: /original-bsd/sys/luna68k/luna68k/locore.s (revision d82abd5c)
1/*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1992 OMRON Corporation.
4 * Copyright (c) 1980, 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department.
10 *
11 * %sccs.include.redist.c%
12 *
13 * from: Utah $Hdr: locore.s 1.62 92/01/20$
14 * from: hp300/hp300/locore.s	8.5 (Berkeley) 11/14/93
15 *
16 *	@(#)locore.s	8.4 (Berkeley) 12/06/93
17 */
18
19/*
20 * STACKCHECK enables two types of kernel stack checking:
21 *	1. stack "overflow".  On every clock interrupt we ensure that
22 *	   the current kernel stack has not grown into the user struct
23 *	   page, i.e. size exceeded UPAGES-1 pages.
24 *	2. stack "underflow".  Before every rte to user mode we ensure
25 *	   that we will be exactly at the base of the stack after the
26 *	   exception frame has been popped.
27 * Both checks are performed at splclock since they operate on the
28 * global temporary stack.
29 */
30/* #define	STACKCHECK */
31
32#include "assym.s"
33#include <luna68k/luna68k/vectors.s>
34
35/*
36 * Temporary stack for a variety of purposes.
37 * Try and make this the first thing is the data segment so it
38 * is page aligned.  Note that if we overflow here, we run into
39 * our text segment.
40 */
41	.data
42	.space	NBPG
43tmpstk:
44
45	.text
46/*
47 * This is where we wind up if the kernel jumps to location 0.
48 * (i.e. a bogus PC)  This is known to immediately follow the vector
49 * table and is hence at 0x400 (see reset vector in vectors.s).
50 */
51	.globl	_panic
52	pea	Ljmp0panic
53	jbsr	_panic
54	/* NOTREACHED */
55Ljmp0panic:
56	.asciz	"kernel jump to zero"
57	.even
58
59/*
60 * Do a dump.
61 * Called by auto-restart.
62 */
63	.globl	_dumpsys
64	.globl	_doadump
65_doadump:
66	jbsr	_dumpsys
67	jbsr	_doboot
68	/*NOTREACHED*/
69
70/*
71 * Trap/interrupt vector routines
72 */
73
74	.globl	_trap, _nofault, _longjmp
75_buserr:
76	tstl	_nofault		| device probe?
77	jeq	Lberr			| no, handle as usual
78	movl	_nofault,sp@-		| yes,
79	jbsr	_longjmp		|  longjmp(nofault)
80Lberr:
81#if defined(LUNA2)
82	cmpl	#-2,_mmutype		| 68040?
83	jne	_addrerr		| no, skip
84	clrl	sp@-			| stack adjust count
85	moveml	#0xFFFF,sp@-		| save user registers
86	movl	usp,a0			| save the user SP
87	movl	a0,sp@(FR_SP)		|   in the savearea
88	lea	sp@(FR_HW),a1		| grab base of HW berr frame
89	moveq	#0,d0
90	movw	a1@(12),d0		| grab SSW
91	movl	a1@(20),d1		| and fault VA
92	btst	#11,d0			| check for mis-aligned access
93	jeq	Lberr2			| no, skip
94	addl	#3,d1			| yes, get into next page
95	andl	#PG_FRAME,d1		| and truncate
96Lberr2:
97	movl	d1,sp@-			| push fault VA
98	movl	d0,sp@-			| and padded SSW
99	btst	#10,d0			| ATC bit set?
100	jeq	Lisberr			| no, must be a real bus error
101	movc	dfc,d1			| yes, get MMU fault
102	movc	d0,dfc			| store faulting function code
103	movl	sp@(4),a0		| get faulting address
104	.word	0xf568			| ptestr a0@
105	movc	d1,dfc
106	.long	0x4e7a0805		| movc mmusr,d0
107	movw	d0,sp@			| save (ONLY LOW 16 BITS!)
108	jra	Lismerr
109#endif
110_addrerr:
111	clrl	sp@-			| stack adjust count
112	moveml	#0xFFFF,sp@-		| save user registers
113	movl	usp,a0			| save the user SP
114	movl	a0,sp@(FR_SP)		|   in the savearea
115	lea	sp@(FR_HW),a1		| grab base of HW berr frame
116#if defined(LUNA2)
117	cmpl	#-2,_mmutype		| 68040?
118	jne	Lbenot040		| no, skip
119	movl	a1@(8),sp@-		| yes, push fault address
120	clrl	sp@-			| no SSW for address fault
121	jra	Lisaerr			| go deal with it
122Lbenot040:
123#endif
124	moveq	#0,d0
125	movw	a1@(10),d0		| grab SSW for fault processing
126	btst	#12,d0			| RB set?
127	jeq	LbeX0			| no, test RC
128	bset	#14,d0			| yes, must set FB
129	movw	d0,a1@(10)		| for hardware too
130LbeX0:
131	btst	#13,d0			| RC set?
132	jeq	LbeX1			| no, skip
133	bset	#15,d0			| yes, must set FC
134	movw	d0,a1@(10)		| for hardware too
135LbeX1:
136	btst	#8,d0			| data fault?
137	jeq	Lbe0			| no, check for hard cases
138	movl	a1@(16),d1		| fault address is as given in frame
139	jra	Lbe10			| thats it
140Lbe0:
141	btst	#4,a1@(6)		| long (type B) stack frame?
142	jne	Lbe4			| yes, go handle
143	movl	a1@(2),d1		| no, can use save PC
144	btst	#14,d0			| FB set?
145	jeq	Lbe3			| no, try FC
146	addql	#4,d1			| yes, adjust address
147	jra	Lbe10			| done
148Lbe3:
149	btst	#15,d0			| FC set?
150	jeq	Lbe10			| no, done
151	addql	#2,d1			| yes, adjust address
152	jra	Lbe10			| done
153Lbe4:
154	movl	a1@(36),d1		| long format, use stage B address
155	btst	#15,d0			| FC set?
156	jeq	Lbe10			| no, all done
157	subql	#2,d1			| yes, adjust address
158Lbe10:
159	movl	d1,sp@-			| push fault VA
160	movl	d0,sp@-			| and padded SSW
161	movw	a1@(6),d0		| get frame format/vector offset
162	andw	#0x0FFF,d0		| clear out frame format
163	cmpw	#12,d0			| address error vector?
164	jeq	Lisaerr			| yes, go to it
165	movl	d1,a0			| fault address
166	ptestr	#1,a0@,#7		| do a table search
167	pmove	psr,sp@			| save result
168	btst	#7,sp@			| bus error bit set?
169	jeq	Lismerr			| no, must be MMU fault
170	clrw	sp@			| yes, re-clear pad word
171	jra	Lisberr			| and process as normal bus error
172Lismerr:
173	movl	#T_MMUFLT,sp@-		| show that we are an MMU fault
174	jra	Ltrapnstkadj		| and deal with it
175Lisaerr:
176	movl	#T_ADDRERR,sp@-		| mark address error
177	jra	Ltrapnstkadj		| and deal with it
178Lisberr:
179	movl	#T_BUSERR,sp@-		| mark bus error
180Ltrapnstkadj:
181	jbsr	_trap			| handle the error
182	lea	sp@(12),sp		| pop value args
183	movl	sp@(FR_SP),a0		| restore user SP
184	movl	a0,usp			|   from save area
185	movw	sp@(FR_ADJ),d0		| need to adjust stack?
186	jne	Lstkadj			| yes, go to it
187	moveml	sp@+,#0x7FFF		| no, restore most user regs
188	addql	#8,sp			| toss SSP and stkadj
189	jra	rei			| all done
190Lstkadj:
191	lea	sp@(FR_HW),a1		| pointer to HW frame
192	addql	#8,a1			| source pointer
193	movl	a1,a0			| source
194	addw	d0,a0			|  + hole size = dest pointer
195	movl	a1@-,a0@-		| copy
196	movl	a1@-,a0@-		|  8 bytes
197	movl	a0,sp@(FR_SP)		| new SSP
198	moveml	sp@+,#0x7FFF		| restore user registers
199	movl	sp@,sp			| and our SP
200	jra	rei			| all done
201
202/*
203 * FP exceptions.
204 */
205_fpfline:
206#if defined(LUNA2)
207	cmpw	#0x202c,sp@(6)		| format type 2?
208	jne	_illinst		| no, not an FP emulation
209#ifdef HPFPLIB
210	.globl fpsp_unimp
211	jmp	fpsp_unimp		| yes, go handle it
212#else
213	clrl	sp@-			| stack adjust count
214	moveml	#0xFFFF,sp@-		| save registers
215	moveq	#T_FPEMULI,d0		| denote as FP emulation trap
216	jra	fault			| do it
217#endif
218#else
219	jra	_illinst
220#endif
221
222_fpunsupp:
223#if defined(LUNA2)
224	cmpl	#-2,_mmutype		| 68040?
225	jne	_illinst		| no, treat as illinst
226#ifdef HPFPLIB
227	.globl	fpsp_unsupp
228	jmp	fpsp_unsupp		| yes, go handle it
229#else
230	clrl	sp@-			| stack adjust count
231	moveml	#0xFFFF,sp@-		| save registers
232	moveq	#T_FPEMULD,d0		| denote as FP emulation trap
233	jra	fault			| do it
234#endif
235#else
236	jra	_illinst
237#endif
238
239/*
240 * Handles all other FP coprocessor exceptions.
241 * Note that since some FP exceptions generate mid-instruction frames
242 * and may cause signal delivery, we need to test for stack adjustment
243 * after the trap call.
244 */
245_fpfault:
246#ifdef FPCOPROC
247	clrl	sp@-		| stack adjust count
248	moveml	#0xFFFF,sp@-	| save user registers
249	movl	usp,a0		| and save
250	movl	a0,sp@(FR_SP)	|   the user stack pointer
251	clrl	sp@-		| no VA arg
252	movl	_curpcb,a0	| current pcb
253	lea	a0@(PCB_FPCTX),a0 | address of FP savearea
254	fsave	a0@		| save state
255	tstb	a0@		| null state frame?
256	jeq	Lfptnull	| yes, safe
257	clrw	d0		| no, need to tweak BIU
258	movb	a0@(1),d0	| get frame size
259	bset	#3,a0@(0,d0:w)	| set exc_pend bit of BIU
260Lfptnull:
261	fmovem	fpsr,sp@-	| push fpsr as code argument
262	frestore a0@		| restore state
263	movl	#T_FPERR,sp@-	| push type arg
264	jra	Ltrapnstkadj	| call trap and deal with stack cleanup
265#else
266	jra	_badtrap	| treat as an unexpected trap
267#endif
268
269#ifdef HPFPLIB
270/*
271 * We wind up here from the 040 FP emulation library after
272 * the exception has been processed.
273 */
274	.globl	_fault
275_fault:
276	subql	#4,sp		| space for rts addr
277	movl	d0,sp@-		| scratch register
278	movw	sp@(14),d0	| get vector offset
279	andl	#0xFFF,d0	| mask out frame type and clear high word
280	cmpl	#0x100,d0	| HP-UX style reschedule trap?
281	jne	Lfault1		| no, skip
282	movl	sp@+,d0		| restore scratch register
283	addql	#4,sp		| pop space
284	jra	Lrei1		| go do AST
285Lfault1:
286	cmpl	#0xC0,d0	| FP exception?
287	jlt	Lfault2		| no, skip
288	movl	sp@+,d0		| yes, backoff
289	addql	#4,sp		|  and prepare for normal trap frame
290	jra	_fpfault	| go to it
291Lfault2:
292	addl	#Lvectab,d0	| convert to vector table offset
293	exg	d0,a0
294	movl	a0@,sp@(4) 	| get exception vector and save for rts
295	exg	d0,a0
296	movl	sp@+,d0		|   scratch registers
297	rts			| return to handler from vectab
298#endif
299
300/*
301 * Coprocessor and format errors can generate mid-instruction stack
302 * frames and cause signal delivery hence we need to check for potential
303 * stack adjustment.
304 */
305_coperr:
306	clrl	sp@-		| stack adjust count
307	moveml	#0xFFFF,sp@-
308	movl	usp,a0		| get and save
309	movl	a0,sp@(FR_SP)	|   the user stack pointer
310	clrl	sp@-		| no VA arg
311	clrl	sp@-		| or code arg
312	movl	#T_COPERR,sp@-	| push trap type
313	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
314
315_fmterr:
316	clrl	sp@-		| stack adjust count
317	moveml	#0xFFFF,sp@-
318	movl	usp,a0		| get and save
319	movl	a0,sp@(FR_SP)	|   the user stack pointer
320	clrl	sp@-		| no VA arg
321	clrl	sp@-		| or code arg
322	movl	#T_FMTERR,sp@-	| push trap type
323	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
324
325/*
326 * Other exceptions only cause four and six word stack frame and require
327 * no post-trap stack adjustment.
328 */
329_illinst:
330	clrl	sp@-
331	moveml	#0xFFFF,sp@-
332	moveq	#T_ILLINST,d0
333	jra	fault
334
335_zerodiv:
336	clrl	sp@-
337	moveml	#0xFFFF,sp@-
338	moveq	#T_ZERODIV,d0
339	jra	fault
340
341_chkinst:
342	clrl	sp@-
343	moveml	#0xFFFF,sp@-
344	moveq	#T_CHKINST,d0
345	jra	fault
346
347_trapvinst:
348	clrl	sp@-
349	moveml	#0xFFFF,sp@-
350	moveq	#T_TRAPVINST,d0
351	jra	fault
352
353_privinst:
354	clrl	sp@-
355	moveml	#0xFFFF,sp@-
356	moveq	#T_PRIVINST,d0
357	jra	fault
358
359	.globl	fault
360fault:
361	movl	usp,a0			| get and save
362	movl	a0,sp@(FR_SP)		|   the user stack pointer
363	clrl	sp@-			| no VA arg
364	clrl	sp@-			| or code arg
365	movl	d0,sp@-			| push trap type
366	jbsr	_trap			| handle trap
367	lea	sp@(12),sp		| pop value args
368	movl	sp@(FR_SP),a0		| restore
369	movl	a0,usp			|   user SP
370	moveml	sp@+,#0x7FFF		| restore most user regs
371	addql	#8,sp			| pop SP and stack adjust
372	jra	rei			| all done
373
374	.globl	_straytrap
375_badtrap:
376	moveml	#0xC0C0,sp@-		| save scratch regs
377	movw	sp@(22),sp@-		| push exception vector info
378	clrw	sp@-
379	movl	sp@(22),sp@-		| and PC
380	jbsr	_straytrap		| report
381	addql	#8,sp			| pop args
382	moveml	sp@+,#0x0303		| restore regs
383	jra	rei			| all done
384
385	.globl	_syscall
386_trap0:
387	clrl	sp@-			| stack adjust count
388	moveml	#0xFFFF,sp@-		| save user registers
389	movl	usp,a0			| save the user SP
390	movl	a0,sp@(FR_SP)		|   in the savearea
391	movl	d0,sp@-			| push syscall number
392	jbsr	_syscall		| handle it
393	addql	#4,sp			| pop syscall arg
394	movl	sp@(FR_SP),a0		| grab and restore
395	movl	a0,usp			|   user SP
396	moveml	sp@+,#0x7FFF		| restore most registers
397	addql	#8,sp			| pop SP and stack adjust
398	jra	rei			| all done
399
400/*
401 * trap1 is sigreturn and trap2 is breakpoint.
402 */
403_trap1:
404	jra	sigreturn		| trap1 is sigreturn
405
406_trap2:
407	jra	_trace			| trap2 is breakpoint
408
409/*
410 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
411 *	cachectl(command, addr, length)
412 * command in d0, addr in a1, length in d1
413 */
414	.globl	_cachectl
415_trap12:
416	movl	d1,sp@-			| push length
417	movl	a1,sp@-			| push addr
418	movl	d0,sp@-			| push command
419	jbsr	_cachectl		| do it
420	lea	sp@(12),sp		| pop args
421	jra	rei			| all done
422
423/*
424 * Trap 15 is used for:
425 *	- KGDB traps
426 *	- trace traps for SUN binaries (not fully supported yet)
427 * We just pass it on and let trap() sort it all out
428 */
429_trap15:
430	clrl	sp@-
431	moveml	#0xFFFF,sp@-
432#ifdef KGDB
433	moveq	#T_TRAP15,d0
434	movw	sp@(FR_HW),d1		| get PSW
435	andw	#PSL_S,d1		| from user mode?
436	jeq	fault			| yes, just a regular fault
437	movl	d0,sp@-
438	.globl	_kgdb_trap_glue
439	jbsr	_kgdb_trap_glue		| returns if no debugger
440	addl	#4,sp
441#endif
442	moveq	#T_TRAP15,d0
443	jra	fault
444
445/*
446 * Hit a breakpoint (trap 1 or 2) instruction.
447 * Push the code and treat as a normal fault.
448 */
449_trace:
450	clrl	sp@-
451	moveml	#0xFFFF,sp@-
452#ifdef KGDB
453	moveq	#T_TRACE,d0
454	movw	sp@(FR_HW),d1		| get SSW
455	andw	#PSL_S,d1		| from user mode?
456	jeq	fault			| no, regular fault
457	movl	d0,sp@-
458	jbsr	_kgdb_trap_glue		| returns if no debugger
459	addl	#4,sp
460#endif
461	moveq	#T_TRACE,d0
462	jra	fault
463
464/*
465 * The sigreturn() syscall comes here.  It requires special handling
466 * because we must open a hole in the stack to fill in the (possibly much
467 * larger) original stack frame.
468 */
469sigreturn:
470	lea	sp@(-84),sp		| leave enough space for largest frame
471	movl	sp@(84),sp@		| move up current 8 byte frame
472	movl	sp@(88),sp@(4)
473	movl	#84,sp@-		| default: adjust by 84 bytes
474	moveml	#0xFFFF,sp@-		| save user registers
475	movl	usp,a0			| save the user SP
476	movl	a0,sp@(FR_SP)		|   in the savearea
477	movl	#SYS_sigreturn,sp@-	| push syscall number
478	jbsr	_syscall		| handle it
479	addql	#4,sp			| pop syscall#
480	movl	sp@(FR_SP),a0		| grab and restore
481	movl	a0,usp			|   user SP
482	lea	sp@(FR_HW),a1		| pointer to HW frame
483	movw	sp@(FR_ADJ),d0		| do we need to adjust the stack?
484	jeq	Lsigr1			| no, just continue
485	moveq	#92,d1			| total size
486	subw	d0,d1			|  - hole size = frame size
487	lea	a1@(92),a0		| destination
488	addw	d1,a1			| source
489	lsrw	#1,d1			| convert to word count
490	subqw	#1,d1			| minus 1 for dbf
491Lsigrlp:
492	movw	a1@-,a0@-		| copy a word
493	dbf	d1,Lsigrlp		| continue
494	movl	a0,a1			| new HW frame base
495Lsigr1:
496	movl	a1,sp@(FR_SP)		| new SP value
497	moveml	sp@+,#0x7FFF		| restore user registers
498	movl	sp@,sp			| and our SP
499	jra	rei			| all done
500
501/*
502 * Interrupt handlers.
503 * All DIO device interrupts are auto-vectored.  Most can be configured
504 * to interrupt in the range IPL2 to IPL5.  Here are our assignments:
505 *
506 *	Level 0:	Spurious: ignored.
507 *	Level 1:	(low XP)
508 *	Level 2:	SCSI
509 *	Level 3:	LANCE
510 *	Level 4:	[PC98]
511 *	Level 5:	Clock
512 *	Level 6:	RS232C
513 *	Level 7:	Non-maskable: parity errors, Abort SW
514 */
515	.globl	_hardclock, _nmihand
516
517_spurintr:
518	addql	#1,_intrcnt+0
519	addql	#1,_cnt+V_INTR
520	jra	rei
521
522_lev1intr:
523	addql	#1,_intrcnt+4
524	addql	#1,_cnt+V_INTR
525	jra	rei			| XP not surpported yet	XXXX
526
527_lev2intr:
528	addql	#1,_intrcnt+8
529	moveml	#0xC0C0,sp@-
530	jbsr	__scintr
531	moveml	sp@+,#0x0303
532	addql	#1,_cnt+V_INTR
533	jra	rei
534
535_lev3intr:
536	addql	#1,_intrcnt+12
537	moveml	#0xC0C0,sp@-
538	jbsr	__leintr
539	moveml	sp@+,#0x0303
540	addql	#1,_cnt+V_INTR
541	jra	rei
542
543_lev4intr:
544	addql	#1,_intrcnt+16
545	addql	#1,_cnt+V_INTR
546	jra	rei			| EX-PC not surpported yet XXXX
547
548_lev6intr:
549	addql	#1,_intrcnt+24
550	moveml	#0xC0C0,sp@-
551	jbsr	__siointr
552	moveml	sp@+,#0x0303
553	addql	#1,_cnt+V_INTR
554	jra	rei
555
556_lev5intr:
557#ifdef STACKCHECK
558	.globl	_panicstr,_badkstack
559	cmpl	#_kstack+NBPG,sp	| are we still in stack page?
560	jcc	Lstackok		| yes, continue normally
561	tstl	_curproc		| if !curproc could have switch_exited,
562	jeq	Lstackok		|     might be on tmpstk
563	tstl	_panicstr		| have we paniced?
564	jne	Lstackok		| yes, do not re-panic
565	movl	sp@(4),tmpstk-4		| no, copy common
566	movl	sp@,tmpstk-8		|  frame info
567	movl	sp,tmpstk-16		| no, save original SP
568	lea	tmpstk-16,sp		| switch to tmpstk
569	moveml	#0xFFFE,sp@-		| push remaining registers
570	movl	#1,sp@-			| is an overflow
571	jbsr	_badkstack		| badkstack(1, frame)
572	addql	#4,sp
573	moveml	sp@+,#0x7FFF		| restore most registers
574	movl	sp@,sp			| and SP
575Lstackok:
576#endif
577	moveml	#0xC0C0,sp@-
578	lea	sp@(16),a1		| a1 = &clockframe
579	btst	#CLK_INT,CLOCK_REG 	| system-clock intrrupt?
580	jeq	Lnottimer		| no, skip hardclock
581	movb	#CLK_CLR,CLOCK_REG	| clear system-clock interrupt
582        tstl	_clock_on		| system-clock started?
583        jeq	Lnottimer		| no, skip hardclock
584	addql	#1,_intrcnt+28		| count hardclock interrupt
585	movl	a1,sp@-
586	jbsr	_hardclock		| hardclock(&frame)
587	addql	#4,sp
588Lnottimer:
589	moveml	sp@+,#0x0303		| restore scratch regs
590	addql	#1,_cnt+V_INTR		| chalk up another interrupt
591	jra	rei			| all done
592
593_lev7intr:
594	addql	#1,_intrcnt+36
595	clrl	sp@-			| pad SR to longword
596	moveml	#0xFFFF,sp@-		| save registers
597	movl	usp,a0			| and save
598	movl	a0,sp@(FR_SP)		|   the user stack pointer
599	jbsr	_nmihand		| call handler
600	movl	sp@(FR_SP),a0		| restore
601	movl	a0,usp			|   user SP
602	moveml	sp@+,#0x7FFF		| and remaining registers
603	addql	#8,sp			| pop SSP and align word
604	jra	rei			| all done
605
606/*
607 * Emulation of VAX REI instruction.
608 *
609 * This code deals with checking for and servicing ASTs
610 * (profiling, scheduling) and software interrupts (network, softclock).
611 * We check for ASTs first, just like the VAX.  To avoid excess overhead
612 * the T_ASTFLT handling code will also check for software interrupts so we
613 * do not have to do it here.  After identifing that we need an AST we
614 * drop the IPL to allow device interrupts.
615 *
616 * This code is complicated by the fact that sendsig may have been called
617 * necessitating a stack cleanup.
618 */
619	.comm	_ssir,1
620	.globl	_astpending
621rei:
622#ifdef STACKCHECK
623	tstl	_panicstr		| have we paniced?
624	jne	Ldorte1			| yes, do not make matters worse
625#endif
626	tstl	_astpending		| AST pending?
627	jeq	Lchksir			| no, go check for SIR
628Lrei1:
629	btst	#5,sp@			| yes, are we returning to user mode?
630	jne	Lchksir			| no, go check for SIR
631	movw	#PSL_LOWIPL,sr		| lower SPL
632	clrl	sp@-			| stack adjust
633	moveml	#0xFFFF,sp@-		| save all registers
634	movl	usp,a1			| including
635	movl	a1,sp@(FR_SP)		|    the users SP
636	clrl	sp@-			| VA == none
637	clrl	sp@-			| code == none
638	movl	#T_ASTFLT,sp@-		| type == async system trap
639	jbsr	_trap			| go handle it
640	lea	sp@(12),sp		| pop value args
641	movl	sp@(FR_SP),a0		| restore user SP
642	movl	a0,usp			|   from save area
643	movw	sp@(FR_ADJ),d0		| need to adjust stack?
644	jne	Laststkadj		| yes, go to it
645	moveml	sp@+,#0x7FFF		| no, restore most user regs
646	addql	#8,sp			| toss SP and stack adjust
647#ifdef STACKCHECK
648	jra	Ldorte
649#else
650	rte				| and do real RTE
651#endif
652Laststkadj:
653	lea	sp@(FR_HW),a1		| pointer to HW frame
654	addql	#8,a1			| source pointer
655	movl	a1,a0			| source
656	addw	d0,a0			|  + hole size = dest pointer
657	movl	a1@-,a0@-		| copy
658	movl	a1@-,a0@-		|  8 bytes
659	movl	a0,sp@(FR_SP)		| new SSP
660	moveml	sp@+,#0x7FFF		| restore user registers
661	movl	sp@,sp			| and our SP
662#ifdef STACKCHECK
663	jra	Ldorte
664#else
665	rte				| and do real RTE
666#endif
667Lchksir:
668	tstb	_ssir			| SIR pending?
669	jeq	Ldorte			| no, all done
670	movl	d0,sp@-			| need a scratch register
671	movw	sp@(4),d0		| get SR
672	andw	#PSL_IPL7,d0		| mask all but IPL
673	jne	Lnosir			| came from interrupt, no can do
674	movl	sp@+,d0			| restore scratch register
675Lgotsir:
676	movw	#SPL1,sr		| prevent others from servicing int
677	tstb	_ssir			| too late?
678	jeq	Ldorte			| yes, oh well...
679	clrl	sp@-			| stack adjust
680	moveml	#0xFFFF,sp@-		| save all registers
681	movl	usp,a1			| including
682	movl	a1,sp@(FR_SP)		|    the users SP
683	clrl	sp@-			| VA == none
684	clrl	sp@-			| code == none
685	movl	#T_SSIR,sp@-		| type == software interrupt
686	jbsr	_trap			| go handle it
687	lea	sp@(12),sp		| pop value args
688	movl	sp@(FR_SP),a0		| restore
689	movl	a0,usp			|   user SP
690	moveml	sp@+,#0x7FFF		| and all remaining registers
691	addql	#8,sp			| pop SP and stack adjust
692#ifdef STACKCHECK
693	jra	Ldorte
694#else
695	rte
696#endif
697Lnosir:
698	movl	sp@+,d0			| restore scratch register
699Ldorte:
700#ifdef STACKCHECK
701	movw	#SPL6,sr		| avoid trouble
702	btst	#5,sp@			| are we returning to user mode?
703	jne	Ldorte1			| no, skip it
704	movl	a6,tmpstk-20
705	movl	d0,tmpstk-76
706	moveq	#0,d0
707	movb	sp@(6),d0		| get format/vector
708	lsrl	#3,d0			| convert to index
709	lea	_exframesize,a6		|  into exframesize
710	addl	d0,a6			|  to get pointer to correct entry
711	movw	a6@,d0			| get size for this frame
712	addql	#8,d0			| adjust for unaccounted for bytes
713	lea	_kstackatbase,a6	| desired stack base
714	subl	d0,a6			|   - frame size == our stack
715	cmpl	a6,sp			| are we where we think?
716	jeq	Ldorte2			| yes, skip it
717	lea	tmpstk,a6		| will be using tmpstk
718	movl	sp@(4),a6@-		| copy common
719	movl	sp@,a6@-		|   frame info
720	clrl	a6@-
721	movl	sp,a6@-			| save sp
722	subql	#4,a6			| skip over already saved a6
723	moveml	#0x7FFC,a6@-		| push remaining regs (d0/a6/a7 done)
724	lea	a6@(-4),sp		| switch to tmpstk (skip saved d0)
725	clrl	sp@-			| is an underflow
726	jbsr	_badkstack		| badkstack(0, frame)
727	addql	#4,sp
728	moveml	sp@+,#0x7FFF		| restore most registers
729	movl	sp@,sp			| and SP
730	rte
731Ldorte2:
732	movl	tmpstk-76,d0
733	movl	tmpstk-20,a6
734Ldorte1:
735#endif
736	rte				| real return
737
738/*
739 * Kernel access to the current processes kernel stack is via a fixed
740 * virtual address.  It is at the same address as in the users VA space.
741 * Umap contains the KVA of the first of UPAGES PTEs mapping VA _kstack.
742 */
743	.data
744	.set	_kstack,KERNELSTACK	| KERNELSTACK(0x3ff00000) != USRSTACK
745_Umap:	.long	0
746	.globl	_kstack, _Umap
747
748/*
749 * Initialization
750 *
751 * Kernel is loaded at 0.
752 * VBR contains zero from ROM.  Exceptions will continue to vector
753 * through ROM until MMU is turned on at which time they will vector
754 * through our table (vectors.s).
755 */
756	.comm	_lowram,4
757
758	.text
759	.globl	_edata
760	.globl	_etext,_end
761	.globl	start
762start:
763	movw	#PSL_HIGHIPL,sr		| no interrupts
764	lea	tmpstk,sp		| give ourselves a temporary stack
765	clrl	d0			| XXXX if loader set vbr = 0
766	movc	d0,vbr			| XXXX please remove these 2 lines
767/*
768 * a5 contains parameters address from booter.
769 * First, we copy whole parameters to Kernel InterFace Field
770 */
771
772	movl	#KIFF_SIZE,sp@-		| KIFF size
773	pea	_KernInter		| KIFF address
774	pea	a5@			| bootor's KIFF address
775	jbsr	_bcopy
776	lea	sp@(12),sp		| pop value args
777
778	movl	a5@(KI_MAXADDR),d0	| maxaddr
779	moveq	#PGSHIFT,d1
780	lsrl	d1,d0			| convert to page (click) number
781	movl	d0,_maxmem		| argument saved in maxmem
782	movl	d0,_physmem		| physmem = maxmem
783	clrl	_lowram			| lowram = 0
784	movl	#0,a5			| kernel is loaded at 0
785	movl	#CACHE_OFF,d0
786	movc	d0,cacr			| clear and disable on-chip cache(s)
787
788#if defined(LUNA2)
789/* determine our CPU/MMU combo - check for all regardless of kernel config */
790	movl	#0x200,d0		| data freeze bit
791	movc	d0,cacr			|   only exists on 68030
792	movc	cacr,d0			| read it back
793	tstl	d0			| zero?
794	jeq	Lnot68030		| yes, we have 68040(LUNA2)
795	movl	#1,_machineid		| no, must be a LUNA-I
796	movl	#-1,_mmutype		| set to reflect 68030 PMMU
797	jra	Lstart1
798Lnot68030:
799	movl	#2,_machineid		| must be a LUNA-II
800	movl	#-2,_mmutype		| set to reflect 68040 MMU
801#ifdef HPFPLIB
802	movl	#3,_processor		| HP-UX style processor id
803#endif
804Lstart1:
805#endif
806/* set 60 to hz, when running LUNA-I */
807	.globl	_modify_clock_param
808	jbsr	_modify_clock_param
809
810/* initialize source/destination control registers for movs */
811	moveq	#FC_USERD,d0		| user space
812	movc	d0,sfc			|   as source
813	movc	d0,dfc			|   and destination of transfers
814
815/*
816 * LUNA  PIO initialization.
817 */
818	movw	PIO0_A,d0		| dipsw-1,2 (from port A&B)
819	movw	d0,_dipswitch
820
821/* configure kernel and proc0 VA space so we can get going */
822	.globl	_Sysseg, _pmap_bootstrap, _avail_start
823	movl	#_end,d5		| end of static kernel text/data
824	addl	#NBPG-1,d5
825	andl	#PG_FRAME,d5		| round to a page
826	movl	d5,a4			| PA=VA
827	pea	a5@			| firstpa
828	pea	a4@			| nextpa
829	jbsr	_pmap_bootstrap		| bootstrap(firstpa, nextpa)
830	addql	#8,sp
831
832/*
833 * Prepare to enable MMU.
834 */
835	movl	_Sysseg,d1		| system segment table addr read value (a KVA)
836#if defined(LUNA2)
837	cmpl	#-2,_mmutype		| 68040?
838	jne	Lmotommu1		| no, skip
839
840	.long	0x4e7b1807		| movc d1,srp
841/* we must set tt-registers here */
842	movl	#0x403FA040,d0		| tt0 for LUNA2 0x40000000-0x7fffffff
843	.long	0x4e7b0004		| movc d0,itt0
844	.long	0x4e7b0006		| movc d0,dtt0
845	movl	#0x807FA040,d0		| tt1 for LUNA2 0x80000000-0xffffffff
846	.long	0x4e7b0005		| movc d0,itt1
847	.long	0x4e7b0007		| movc d0,dtt1
848	.word	0xf4d8			| cinva bc
849	.word	0xf518			| pflusha
850	movl	#0x8000,d0
851	.long	0x4e7b0003		| movc d0,tc
852	movl	#0x80008000,d0
853	movc	d0,cacr			| turn on both caches
854	jmp	Lenab1
855Lmotommu1:
856#endif
857	lea	_protorp,a0
858	movl	#0x80000202,a0@		| nolimit + share global + 4 byte PTEs
859	movl	d1,a0@(4)		| + segtable address
860	pmove	a0@,srp			| load the supervisor root pointer
861	movl	#0x80000002,a0@		| reinit upper half for CRP loads
862/* we must set tt-registers here */
863	lea	_protott0,a0		| tt0 for LUNA1 0x40000000-0x7fffffff
864	.word	0xf010			| pmove	a0@,mmutt0
865	.word	0x0800
866	lea	_protott1,a0		| tt1 for LUNA1 0x80000000-0xffffffff
867	.word	0xf010			| pmove	a0@,mmutt1
868	.word	0x0c00
869	lea	_mapping_tc,a2
870	movl	#0x82c0aa00,a2@		| value to load TC with
871	pmove	a2@,tc			| load it
872
873/*
874 * Should be running mapped from this point on
875 */
876Lenab1:
877#ifdef FPCOPROC
878/* fpp check */
879	movl	a1,sp@-
880	jbsr	_checkfpp		| check fpp
881	frestore _fppnull		| reset
882	movl	sp@+,a1
883#endif
884/* select the software page size now */
885	lea	tmpstk,sp		| temporary stack
886	jbsr	_vm_set_page_size	| select software page size
887/* set kernel stack, user SP, and initial pcb */
888	lea	_kstack,a1		| proc0 kernel stack
889	lea	a1@(UPAGES*NBPG-4),sp	| set kernel stack to end of area
890	movl	#USRSTACK-4,a2
891	movl	a2,usp			| init user SP
892	movl	_proc0paddr,a1		| get proc0 pcb addr
893	movl	a1,_curpcb		| proc0 is running
894#ifdef FPCOPROC
895	clrl	a1@(PCB_FPCTX)		| ensure null FP context
896	movl	a1,sp@-
897	jbsr	_m68881_restore		| restore it (does not kill a1)
898	addql	#4,sp
899#endif
900/* flush TLB and turn on caches */
901	jbsr	_TBIA			| invalidate TLB
902#if defined(LUNA2)
903	cmpl	#-2,_mmutype		| 68040?
904	jeq	Lnocache0		| yes, cache already on
905#endif
906	movl	#CACHE_ON,d0
907	movc	d0,cacr			| clear cache(s)
908Lnocache0:
909/* final setup for C code */
910	movw	#PSL_LOWIPL,sr		| lower SPL
911	movl	d7,_boothowto		| save reboot flags
912	movl	d6,_bootdev		|   and boot device
913/*
914 * Create a fake exception frame that returns to user mode,
915 * make space for the rest of a fake saved register set, and
916 * pass the first available RAM and a pointer to the register
917 * set to "main()".  "main()" will call "icode()", which fakes
918 * an "execve()" system call, which is why we need to do that
919 * ("main()" sets "u.u_ar0" to point to the register set).
920 * When "main()" returns, we're running in process 1 and have
921 * successfully faked the "execve()".  We load up the registers from
922 * that set; the "rte" loads the PC and PSR, which jumps to "init".
923 */
924  	clrw	sp@-			| vector offset/frame type
925	clrl	sp@-			| PC - filled in by "execve"
926  	movw	#PSL_USER,sp@-		| in user mode
927	clrw	sp@-			| pad SR to longword
928	lea	sp@(-64),sp		| construct space for D0-D7/A0-A7
929	pea	sp@			| addr of space for D0
930	jbsr	_main			| main(firstaddr, r0)
931	addql	#4,sp			| pop args
932#if defined(LUNA2)
933	cmpl	#-2,_mmutype		| 68040?
934	jne	Lnoflush		| no, skip
935	.word	0xf478			| cpusha dc
936	.word	0xf498			| cinva ic
937Lnoflush:
938#endif
939	movl	sp@(60),a0		| grab and load
940	movl	a0,usp			|   user SP
941	moveml	sp@+,#0x7FFF		| load most registers (all but SSP)
942	addql	#6,sp			| pop SSP and align word
943  	rte
944
945/*
946 * Signal "trampoline" code (18 bytes).  Invoked from RTE setup by sendsig().
947 *
948 * Stack looks like:
949 *
950 *	sp+0 ->	signal number
951 *	sp+4	signal specific code
952 *	sp+8	pointer to signal context frame (scp)
953 *	sp+12	address of handler
954 *	sp+16	saved hardware state
955 *			.
956 *			.
957 *	scp+0->	beginning of signal context frame
958 */
959	.globl	_sigcode, _esigcode, _sigcodetrap
960	.data
961_sigcode:
962	movl	sp@(12),a0		| signal handler addr	(4 bytes)
963	jsr	a0@			| call signal handler	(2 bytes)
964	addql	#4,sp			| pop signo		(2 bytes)
965_sigcodetrap:
966	trap	#1			| special syscall entry	(2 bytes)
967	movl	d0,sp@(4)		| save errno		(4 bytes)
968	moveq	#1,d0			| syscall == exit	(2 bytes)
969	trap	#0			| exit(errno)		(2 bytes)
970	.align	2
971_esigcode:
972
973/*
974 * Primitives
975 */
976
977#ifdef __STDC__
978#define EXPORT(name)		.globl _ ## name; _ ## name:
979#else
980#define EXPORT(name)		.globl _/**/name; _/**/name:
981#endif
982#ifdef GPROF
983#if __GNUC__ >= 2
984#define		ENTRY(name)		EXPORT(name) link a6,\#0; jbsr mcount; unlk a6
985#else
986#define		ENTRY(name)		EXPORT(name) link a6,#0; jbsr mcount; unlk a6
987#endif
988#define ALTENTRY(name, rname) ENTRY(name); jra rname+12
989#else
990#define		ENTRY(name)		EXPORT(name)
991#define ALTENTRY(name, rname)		ENTRY(name)
992#endif
993
994/*
995 * For gcc2
996 */
997ENTRY(__main)
998	rts
999
1000/*
1001 * copypage(fromaddr, toaddr)
1002 *
1003 * Optimized version of bcopy for a single page-aligned NBPG byte copy.
1004 */
1005ENTRY(copypage)
1006	movl	sp@(4),a0		| source address
1007	movl	sp@(8),a1		| destination address
1008	movl	#NBPG/32,d0		| number of 32 byte chunks
1009#if defined(LUNA2)
1010	cmpl	#-2,_mmutype		| 68040?
1011	jne	Lmlloop			| no, use movl
1012Lm16loop:
1013	.long	0xf6209000		| move16 a0@+,a1@+
1014	.long	0xf6209000		| move16 a0@+,a1@+
1015	subql	#1,d0
1016	jne	Lm16loop
1017	rts
1018#endif
1019Lmlloop:
1020	movl	a0@+,a1@+
1021	movl	a0@+,a1@+
1022	movl	a0@+,a1@+
1023	movl	a0@+,a1@+
1024	movl	a0@+,a1@+
1025	movl	a0@+,a1@+
1026	movl	a0@+,a1@+
1027	movl	a0@+,a1@+
1028	subql	#1,d0
1029	jne	Lmlloop
1030	rts
1031
1032/*
1033 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
1034 *
1035 * Copy a null terminated string from the user address space into
1036 * the kernel address space.
1037 *
1038 * NOTE: maxlength must be < 64K (due to use of DBcc)
1039 */
1040ENTRY(copyinstr)
1041	movl	_curpcb,a0		| current pcb
1042	movl	#Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults
1043	movl	sp@(4),a0		| a0 = fromaddr
1044	movl	sp@(8),a1		| a1 = toaddr
1045	moveq	#0,d0
1046	movw	sp@(14),d0		| d0 = maxlength
1047	jlt	Lcisflt1		| negative count, error
1048	jeq	Lcisdone		| zero count, all done
1049	subql	#1,d0			| set up for dbeq
1050Lcisloop:
1051	movsb	a0@+,d1			| grab a byte
1052	nop
1053	movb	d1,a1@+			| copy it
1054	dbeq	d0,Lcisloop		| if !null and more, continue
1055	jne	Lcisflt2		| ran out of room, error
1056	moveq	#0,d0			| got a null, all done
1057Lcisdone:
1058	tstl	sp@(16)			| return length desired?
1059	jeq	Lcisret			| no, just return
1060	subl	sp@(4),a0		| determine how much was copied
1061	movl	sp@(16),a1		| return location
1062	movl	a0,a1@			| stash it
1063Lcisret:
1064	movl	_curpcb,a0		| current pcb
1065	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
1066	rts
1067Lcisflt1:
1068	moveq	#EFAULT,d0		| copy fault
1069	jra	Lcisdone
1070Lcisflt2:
1071	moveq	#ENAMETOOLONG,d0	| ran out of space
1072	jra	Lcisdone
1073
1074/*
1075 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1076 *
1077 * Copy a null terminated string from the kernel
1078 * address space to the user address space.
1079 * NOTE: maxlength must be < 64K
1080 */
1081ENTRY(copyoutstr)
1082	movl	_curpcb,a0		| current pcb
1083	movl	#Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults
1084	movl	sp@(4),a0		| a0 = fromaddr
1085	movl	sp@(8),a1		| a1 = toaddr
1086	moveq	#0,d0
1087	movw	sp@(14),d0		| d0 = maxlength
1088	jlt	Lcosflt1		| negative count, error
1089	jeq	Lcosdone		| zero count, all done
1090	subql	#1,d0			| set up for dbeq
1091Lcosloop:
1092	movb	a0@+,d1			| grab a byte
1093	movsb	d1,a1@+			| copy it
1094	nop
1095	dbeq	d0,Lcosloop		| if !null and more, continue
1096	jne	Lcosflt2		| ran out of room, error
1097	moveq	#0,d0			| got a null, all done
1098Lcosdone:
1099	tstl	sp@(16)			| return length desired?
1100	jeq	Lcosret			| no, just return
1101	subl	sp@(4),a0		| determine how much was copied
1102	movl	sp@(16),a1		| return location
1103	movl	a0,a1@			| stash it
1104Lcosret:
1105	movl	_curpcb,a0		| current pcb
1106	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
1107	rts
1108Lcosflt1:
1109	moveq	#EFAULT,d0		| copy fault
1110	jra	Lcosdone
1111Lcosflt2:
1112	moveq	#ENAMETOOLONG,d0	| ran out of space
1113	jra	Lcosdone
1114
1115/*
1116 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1117 *
1118 * Copy a null terminated string from one point to another in
1119 * the kernel address space.
1120 *
1121 * NOTE: maxlength must be < 64K (due to use of DBcc)
1122 */
1123ENTRY(copystr)
1124	movl	sp@(4),a0		| a0 = fromaddr
1125	movl	sp@(8),a1		| a1 = toaddr
1126	moveq	#0,d0
1127	movw	sp@(14),d0		| d0 = maxlength
1128	jlt	Lcsflt1			| negative count, error
1129	jeq	Lcsdone			| zero count, all done
1130	subql	#1,d0			| set up for dbeq
1131Lcsloop:
1132	movb	a0@+,a1@+		| copy a byte
1133	dbeq	d0,Lcsloop		| if !null and more, continue
1134	jne	Lcsflt2			| ran out of room, error
1135	moveq	#0,d0			| got a null, all done
1136Lcsdone:
1137	tstl	sp@(16)			| return length desired?
1138	jeq	Lcsret			| no, just return
1139	subl	sp@(4),a0		| determine how much was copied
1140	movl	sp@(16),a1		| return location
1141	movl	a0,a1@			| stash it
1142Lcsret:
1143	rts
1144Lcsflt1:
1145	moveq	#EFAULT,d0		| copy fault
1146	jra	Lcsdone
1147Lcsflt2:
1148	moveq	#ENAMETOOLONG,d0	| ran out of space
1149	jra	Lcsdone
1150
1151/*
1152 * Copyin(from_user, to_kernel, len)
1153 * Copyout(from_kernel, to_user, len)
1154 *
1155 * Copy specified amount of data between kernel and user space.
1156 *
1157 * XXX both use the DBcc instruction which has 16-bit limitation so only
1158 * 64k units can be copied, where "unit" is either a byte or a longword
1159 * depending on alignment.  To be safe, assume it can copy at most
1160 * 64k bytes.  Don't make MAXBSIZE or MAXPHYS larger than 64k without
1161 * fixing this code!
1162 */
1163ENTRY(copyin)
1164	movl	sp@(12),d0		| get size
1165#ifdef MAPPEDCOPY
1166	.globl	_mappedcopysize,_mappedcopyin
1167	cmpl	_mappedcopysize,d0	| size >= mappedcopysize
1168	jcc	_mappedcopyin		| yes, go do it the new way
1169#endif
1170	movl	d2,sp@-			| scratch register
1171	movl	_curpcb,a0		| current pcb
1172	movl	#Lciflt,a0@(PCB_ONFAULT) | set up to catch faults
1173	tstl	d0			| check count
1174	jlt	Lciflt			| negative, error
1175	jeq	Lcidone			| zero, done
1176	movl	sp@(8),a0		| src address
1177	movl	sp@(12),a1		| dest address
1178	movl	a0,d2
1179	btst	#0,d2			| src address odd?
1180	jeq	Lcieven			| no, go check dest
1181	movsb	a0@+,d1			| yes, get a byte
1182	nop
1183	movb	d1,a1@+			| put a byte
1184	subql	#1,d0			| adjust count
1185	jeq	Lcidone			| exit if done
1186Lcieven:
1187	movl	a1,d2
1188	btst	#0,d2			| dest address odd?
1189	jne	Lcibloop		| yes, must copy by bytes
1190	movl	d0,d2			| no, get count
1191	lsrl	#2,d2			| convert to longwords
1192	jeq	Lcibloop		| no longwords, copy bytes
1193Lcilloop:
1194	movsl	a0@+,d1			| get a long
1195	nop
1196	movl	d1,a1@+			| put a long
1197	subql	#1,d2
1198	jne	Lcilloop		| til done
1199	andl	#3,d0			| what remains
1200	jeq	Lcidone			| all done
1201Lcibloop:
1202	movsb	a0@+,d1			| get a byte
1203	nop
1204	movb	d1,a1@+			| put a byte
1205	subql	#1,d0
1206	jne	Lcibloop		| til done
1207Lcidone:
1208	movl	_curpcb,a0		| current pcb
1209	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1210	movl	sp@+,d2			| restore scratch reg
1211	rts
1212Lciflt:
1213	moveq	#EFAULT,d0		| got a fault
1214	jra	Lcidone
1215
1216ENTRY(copyout)
1217	movl	sp@(12),d0		| get size
1218#ifdef MAPPEDCOPY
1219	.globl	_mappedcopysize,_mappedcopyout
1220	cmpl	_mappedcopysize,d0	| size >= mappedcopysize
1221	jcc	_mappedcopyout		| yes, go do it the new way
1222#endif
1223	movl	d2,sp@-			| scratch register
1224	movl	_curpcb,a0		| current pcb
1225	movl	#Lcoflt,a0@(PCB_ONFAULT) | catch faults
1226	tstl	d0			| check count
1227	jlt	Lcoflt			| negative, error
1228	jeq	Lcodone			| zero, done
1229	movl	sp@(8),a0		| src address
1230	movl	sp@(12),a1		| dest address
1231	movl	a0,d2
1232	btst	#0,d2			| src address odd?
1233	jeq	Lcoeven			| no, go check dest
1234	movb	a0@+,d1			| yes, get a byte
1235	movsb	d1,a1@+			| put a byte
1236	nop
1237	subql	#1,d0			| adjust count
1238	jeq	Lcodone			| exit if done
1239Lcoeven:
1240	movl	a1,d2
1241	btst	#0,d2			| dest address odd?
1242	jne	Lcobloop		| yes, must copy by bytes
1243	movl	d0,d2			| no, get count
1244	lsrl	#2,d2			| convert to longwords
1245	jeq	Lcobloop		| no longwords, copy bytes
1246Lcolloop:
1247	movl	a0@+,d1			| get a long
1248	movsl	d1,a1@+			| put a long
1249	nop
1250	subql	#1,d2
1251	jne	Lcolloop		| til done
1252	andl	#3,d0			| what remains
1253	jeq	Lcodone			| all done
1254Lcobloop:
1255	movb	a0@+,d1			| get a byte
1256	movsb	d1,a1@+			| put a byte
1257	nop
1258	subql	#1,d0
1259	jne	Lcobloop		| til done
1260Lcodone:
1261	movl	_curpcb,a0		| current pcb
1262	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1263	movl	sp@+,d2			| restore scratch reg
1264	rts
1265Lcoflt:
1266	moveq	#EFAULT,d0		| got a fault
1267	jra	Lcodone
1268
1269/*
1270 * non-local gotos
1271 */
1272ENTRY(setjmp)
1273	movl	sp@(4),a0	| savearea pointer
1274	moveml	#0xFCFC,a0@	| save d2-d7/a2-a7
1275	movl	sp@,a0@(48)	| and return address
1276	moveq	#0,d0		| return 0
1277	rts
1278
1279ENTRY(longjmp)
1280	movl	sp@(4),a0
1281	moveml	a0@+,#0xFCFC
1282	movl	a0@,sp@
1283	moveq	#1,d0
1284	rts
1285
1286/*
1287 * The following primitives manipulate the run queues.  _whichqs tells which
1288 * of the 32 queues _qs have processes in them.  Setrunqueue puts processes
1289 * into queues, Remrq removes them from queues.  The running process is on
1290 * no queue, other processes are on a queue related to p->p_priority, divided
1291 * by 4 actually to shrink the 0-127 range of priorities into the 32 available
1292 * queues.
1293 */
1294
1295	.globl	_whichqs,_qs,_cnt,_panic
1296	.globl	_curproc,_want_resched
1297
1298/*
1299 * Setrunqueue(p)
1300 *
1301 * Call should be made at spl6(), and p->p_stat should be SRUN
1302 */
1303ENTRY(setrunqueue)
1304	movl	sp@(4),a0
1305	tstl	a0@(P_BACK)
1306	jeq	Lset1
1307	movl	#Lset2,sp@-
1308	jbsr	_panic
1309Lset1:
1310	clrl	d0
1311	movb	a0@(P_PRIORITY),d0
1312	lsrb	#2,d0
1313	movl	_whichqs,d1
1314	bset	d0,d1
1315	movl	d1,_whichqs
1316	lslb	#3,d0
1317	addl	#_qs,d0
1318	movl	d0,a0@(P_FORW)
1319	movl	d0,a1
1320	movl	a1@(P_BACK),a0@(P_BACK)
1321	movl	a0,a1@(P_BACK)
1322	movl	a0@(P_BACK),a1
1323	movl	a0,a1@(P_FORW)
1324	rts
1325
1326Lset2:
1327	.asciz	"setrunqueue"
1328	.even
1329
1330/*
1331 * Remrq(p)
1332 *
1333 * Call should be made at spl6().
1334 */
1335ENTRY(remrq)
1336	movl	sp@(4),a0
1337	clrl	d0
1338	movb	a0@(P_PRIORITY),d0
1339	lsrb	#2,d0
1340	movl	_whichqs,d1
1341	bclr	d0,d1
1342	jne	Lrem1
1343	movl	#Lrem3,sp@-
1344	jbsr	_panic
1345Lrem1:
1346	movl	d1,_whichqs
1347	movl	a0@(P_FORW),a1
1348	movl	a0@(P_BACK),a1@(P_BACK)
1349	movl	a0@(P_BACK),a1
1350	movl	a0@(P_FORW),a1@(P_FORW)
1351	movl	#_qs,a1
1352	movl	d0,d1
1353	lslb	#3,d1
1354	addl	d1,a1
1355	cmpl	a1@(P_FORW),a1
1356	jeq	Lrem2
1357	movl	_whichqs,d1
1358	bset	d0,d1
1359	movl	d1,_whichqs
1360Lrem2:
1361	clrl	a0@(P_BACK)
1362	rts
1363
1364Lrem3:
1365	.asciz	"remrq"
1366Lsw0:
1367	.asciz	"switch"
1368	.even
1369
1370	.globl	_curpcb
1371	.globl	_masterpaddr	| XXX compatibility (debuggers)
1372	.data
1373_masterpaddr:			| XXX compatibility (debuggers)
1374_curpcb:
1375	.long	0
1376mdpflag:
1377	.byte	0		| copy of proc md_flags low byte
1378	.align	2
1379	.comm	nullpcb,SIZEOF_PCB
1380	.text
1381
1382/*
1383 * At exit of a process, do a switch for the last time.
1384 * The mapping of the pcb at p->p_addr has already been deleted,
1385 * and the memory for the pcb+stack has been freed.
1386 * The ipl is high enough to prevent the memory from being reallocated.
1387 */
1388ENTRY(switch_exit)
1389	movl	#nullpcb,_curpcb	| save state into garbage pcb
1390	lea	tmpstk,sp		| goto a tmp stack
1391	jra	_cpu_switch
1392
1393/*
1394 * When no processes are on the runq, Swtch branches to Idle
1395 * to wait for something to come ready.
1396 */
1397	.globl	idle
1398idle:
1399	stop	#PSL_LOWIPL
1400Idle:
1401	movw	#PSL_HIGHIPL,sr
1402	tstl	_whichqs
1403	jeq	idle
1404	movw	#PSL_LOWIPL,sr
1405	jra	Lsw1
1406
1407Lbadsw:
1408	movl	#Lsw0,sp@-
1409	jbsr	_panic
1410	/*NOTREACHED*/
1411
1412/*
1413 * cpu_switch()
1414 *
1415 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
1416 * entire ATC.  The effort involved in selective flushing may not be
1417 * worth it, maybe we should just flush the whole thing?
1418 *
1419 * NOTE 2: With the new VM layout we now no longer know if an inactive
1420 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1421 * bit).  For now, we just always flush the full ATC.
1422 */
1423ENTRY(cpu_switch)
1424	movl	_curpcb,a0		| current pcb
1425	movw	sr,a0@(PCB_PS)		| save sr before changing ipl
1426#ifdef notyet
1427	movl	_curproc,sp@-		| remember last proc running
1428#endif
1429	clrl	_curproc
1430	addql	#1,_cnt+V_SWTCH
1431
1432Lsw1:
1433	/*
1434	 * Find the highest-priority queue that isn't empty,
1435	 * then take the first proc from that queue.
1436	 */
1437	clrl	d0
1438	lea	_whichqs,a0
1439	movl	a0@,d1
1440Lswchk:
1441	btst	d0,d1
1442	jne	Lswfnd
1443	addqb	#1,d0
1444	cmpb	#32,d0
1445	jne	Lswchk
1446	jra	Idle
1447Lswfnd:
1448	movw	#PSL_HIGHIPL,sr		| lock out interrupts
1449	movl	a0@,d1			| and check again...
1450	bclr	d0,d1
1451	jeq	Lsw1			| proc moved, rescan
1452	movl	d1,a0@			| update whichqs
1453	moveq	#1,d1			| double check for higher priority
1454	lsll	d0,d1			| process (which may have snuck in
1455	subql	#1,d1			| while we were finding this one)
1456	andl	a0@,d1
1457	jeq	Lswok			| no one got in, continue
1458	movl	a0@,d1
1459	bset	d0,d1			| otherwise put this one back
1460	movl	d1,a0@
1461	jra	Lsw1			| and rescan
1462Lswok:
1463	movl	d0,d1
1464	lslb	#3,d1			| convert queue number to index
1465	addl	#_qs,d1			| locate queue (q)
1466	movl	d1,a1
1467	cmpl	a1@(P_FORW),a1		| anyone on queue?
1468	jeq	Lbadsw			| no, panic
1469	movl	a1@(P_FORW),a0		| p = q->p_forw
1470	movl	a0@(P_FORW),a1@(P_FORW)	| q->p_forw = p->p_forw
1471	movl	a0@(P_FORW),a1		| q = p->p_forw
1472	movl	a0@(P_BACK),a1@(P_BACK)	| q->p_back = p->p_back
1473	cmpl	a0@(P_FORW),d1		| anyone left on queue?
1474	jeq	Lsw2			| no, skip
1475	movl	_whichqs,d1
1476	bset	d0,d1			| yes, reset bit
1477	movl	d1,_whichqs
1478Lsw2:
1479	movl	a0,_curproc
1480	clrl	_want_resched
1481#ifdef notyet
1482	movl	sp@+,a1
1483	cmpl	a0,a1			| switching to same proc?
1484	jeq	Lswdone			| yes, skip save and restore
1485#endif
1486	/*
1487	 * Save state of previous process in its pcb.
1488	 */
1489	movl	_curpcb,a1
1490	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1491	movl	usp,a2			| grab USP (a2 has been saved)
1492	movl	a2,a1@(PCB_USP)		| and save it
1493#ifdef FPCOPROC
1494	lea	a1@(PCB_FPCTX),a2	| pointer to FP save area
1495	fsave	a2@			| save FP state
1496	tstb	a2@			| null state frame?
1497	jeq	Lswnofpsave		| yes, all done
1498	fmovem	fp0-fp7,a2@(216)	| save FP general registers
1499	fmovem	fpcr/fpsr/fpi,a2@(312)	| save FP control registers
1500Lswnofpsave:
1501#endif
1502
1503#ifdef DIAGNOSTIC
1504	tstl	a0@(P_WCHAN)
1505	jne	Lbadsw
1506	cmpb	#SRUN,a0@(P_STAT)
1507	jne	Lbadsw
1508#endif
1509	clrl	a0@(P_BACK)		| clear back link
1510	movb	a0@(P_MDFLAG+3),mdpflag	| low byte of p_md.md_flags
1511	movl	a0@(P_ADDR),a1		| get p_addr
1512	movl	a1,_curpcb
1513
1514	/* see if pmap_activate needs to be called; should remove this */
1515	movl	a0@(P_VMSPACE),a0	| vmspace = p->p_vmspace
1516#ifdef DIAGNOSTIC
1517	tstl	a0			| map == VM_MAP_NULL?
1518	jeq	Lbadsw			| panic
1519#endif
1520	lea	a0@(VM_PMAP),a0		| pmap = &vmspace.vm_pmap
1521	tstl	a0@(PM_STCHG)		| pmap->st_changed?
1522	jeq	Lswnochg		| no, skip
1523	pea	a1@			| push pcb (at p_addr)
1524	pea	a0@			| push pmap
1525	jbsr	_pmap_activate		| pmap_activate(pmap, pcb)
1526	addql	#8,sp
1527	movl	_curpcb,a1		| restore p_addr
1528Lswnochg:
1529
1530	movl	#PGSHIFT,d1
1531	movl	a1,d0
1532	lsrl	d1,d0			| convert p_addr to page number
1533	lsll	#2,d0			| and now to Sysmap offset
1534	addl	_Sysmap,d0		| add Sysmap base to get PTE addr
1535#ifdef notdef
1536	movw	#PSL_HIGHIPL,sr		| go crit while changing PTEs
1537#endif
1538	lea	tmpstk,sp		| now goto a tmp stack for NMI
1539	movl	d0,a0			| address of new context
1540	movl	_Umap,a2		| address of PTEs for kstack
1541	moveq	#UPAGES-1,d0		| sizeof kstack
1542Lres1:
1543	movl	a0@+,d1			| get PTE
1544	andl	#~PG_PROT,d1		| mask out old protection
1545	orl	#PG_RW+PG_V,d1		| ensure valid and writable
1546	movl	d1,a2@+			| load it up
1547	dbf	d0,Lres1		| til done
1548#if defined(LUNA2)
1549	cmpl	#-2,_mmutype		| 68040?
1550	jne	Lres1a			| no, skip
1551	.word	0xf518			| yes, pflusha
1552	movl	a1@(PCB_USTP),d0	| get USTP
1553	moveq	#PGSHIFT,d1
1554	lsll	d1,d0			| convert to addr
1555	.long	0x4e7b0806		| movc d0,urp
1556	jra	Lcxswdone
1557Lres1a:
1558#endif
1559	movl	#CACHE_CLR,d0
1560	movc	d0,cacr			| invalidate cache(s)
1561	pflusha				| flush entire TLB
1562	movl	a1@(PCB_USTP),d0	| get USTP
1563	moveq	#PGSHIFT,d1
1564	lsll	d1,d0			| convert to addr
1565	lea	_protorp,a0		| CRP prototype
1566	movl	d0,a0@(4)		| stash USTP
1567	pmove	a0@,crp			| load new user root pointer
1568Lcxswdone:
1569	moveml	a1@(PCB_REGS),#0xFCFC	| and registers
1570	movl	a1@(PCB_USP),a0
1571	movl	a0,usp			| and USP
1572#ifdef FPCOPROC
1573	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1574	tstb	a0@			| null state frame?
1575	jeq	Lresfprest		| yes, easy
1576#if defined(LUNA2)
1577	cmpl	#-2,_mmutype		| 68040?
1578	jne	Lresnot040		| no, skip
1579	clrl	sp@-			| yes...
1580	frestore sp@+			| ...magic!
1581Lresnot040:
1582#endif
1583	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
1584	fmovem	a0@(216),fp0-fp7	| restore FP general registers
1585Lresfprest:
1586	frestore a0@			| restore state
1587#endif
1588	movw	a1@(PCB_PS),sr		| no, restore PS
1589	moveq	#1,d0			| return 1 (for alternate returns)
1590	rts
1591
1592/*
1593 * savectx(pcb, altreturn)
1594 * Update pcb, saving current processor state and arranging
1595 * for alternate return ala longjmp in switch if altreturn is true.
1596 */
1597ENTRY(savectx)
1598	movl	sp@(4),a1
1599	movw	sr,a1@(PCB_PS)
1600	movl	usp,a0			| grab USP
1601	movl	a0,a1@(PCB_USP)		| and save it
1602	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1603#ifdef FPCOPROC
1604	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1605	fsave	a0@			| save FP state
1606	tstb	a0@			| null state frame?
1607	jeq	Lsvnofpsave		| yes, all done
1608	fmovem	fp0-fp7,a0@(216)	| save FP general registers
1609	fmovem	fpcr/fpsr/fpi,a0@(312)	| save FP control registers
1610Lsvnofpsave:
1611#endif
1612	tstl	sp@(8)			| altreturn?
1613	jeq	Lsavedone
1614	movl	sp,d0			| relocate current sp relative to a1
1615	subl	#_kstack,d0		|   (sp is relative to kstack):
1616	addl	d0,a1			|   a1 += sp - kstack;
1617	movl	sp@,a1@			| write return pc at (relocated) sp@
1618Lsavedone:
1619	moveq	#0,d0			| return 0
1620	rts
1621
1622/*
1623 * {fu,su},{byte,sword,word}
1624 */
1625ALTENTRY(fuiword, _fuword)
1626ENTRY(fuword)
1627	movl	sp@(4),a0		| address to read
1628	movl	_curpcb,a1		| current pcb
1629	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1630	movsl	a0@,d0			| do read from user space
1631	nop
1632	jra	Lfsdone
1633
1634ENTRY(fusword)
1635	movl	sp@(4),a0
1636	movl	_curpcb,a1		| current pcb
1637	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1638	moveq	#0,d0
1639	movsw	a0@,d0			| do read from user space
1640	nop
1641	jra	Lfsdone
1642
1643/* Just like fusword, but tells trap code not to page in. */
1644ENTRY(fuswintr)
1645	movl	sp@(4),a0
1646	movl	_curpcb,a1
1647	movl	#_fswintr,a1@(PCB_ONFAULT)
1648	moveq	#0,d0
1649	movsw	a0@,d0
1650	nop
1651	jra	Lfsdone
1652
1653ALTENTRY(fuibyte, _fubyte)
1654ENTRY(fubyte)
1655	movl	sp@(4),a0		| address to read
1656	movl	_curpcb,a1		| current pcb
1657	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1658	moveq	#0,d0
1659	movsb	a0@,d0			| do read from user space
1660	nop
1661	jra	Lfsdone
1662
1663Lfserr:
1664	moveq	#-1,d0			| error indicator
1665Lfsdone:
1666	clrl	a1@(PCB_ONFAULT) 	| clear fault address
1667	rts
1668
1669/* Just like Lfserr, but the address is different (& exported). */
1670	.globl	_fswintr
1671_fswintr:
1672	moveq	#-1,d0
1673	jra	Lfsdone
1674
1675
1676/*
1677 * Write a longword in user instruction space.
1678 * Largely the same as suword but with a final i-cache purge on those
1679 * machines with split caches.
1680 */
1681ENTRY(suiword)
1682	movl	sp@(4),a0		| address to write
1683	movl	sp@(8),d0		| value to put there
1684	movl	_curpcb,a1		| current pcb
1685	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1686	movsl	d0,a0@			| do write to user space
1687	nop
1688	moveq	#0,d0			| indicate no fault
1689#if defined(LUNA2)
1690	cmpl	#-2,_mmutype		| 68040?
1691	jne	Lsuicpurge		| no, skip
1692	.word	0xf498			| cinva ic (XXX overkill)
1693	jra	Lfsdone
1694Lsuicpurge:
1695#endif
1696	movl	#IC_CLEAR,d1
1697	movc	d1,cacr			| invalidate i-cache
1698	jra	Lfsdone
1699
1700ENTRY(suword)
1701	movl	sp@(4),a0		| address to write
1702	movl	sp@(8),d0		| value to put there
1703	movl	_curpcb,a1		| current pcb
1704	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1705	movsl	d0,a0@			| do write to user space
1706	nop
1707	moveq	#0,d0			| indicate no fault
1708	jra	Lfsdone
1709
1710ENTRY(susword)
1711	movl	sp@(4),a0		| address to write
1712	movw	sp@(10),d0		| value to put there
1713	movl	_curpcb,a1		| current pcb
1714	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1715	movsw	d0,a0@			| do write to user space
1716	nop
1717	moveq	#0,d0			| indicate no fault
1718	jra	Lfsdone
1719
1720ENTRY(suswintr)
1721	movl	sp@(4),a0
1722	movw	sp@(10),d0
1723	movl	_curpcb,a1
1724	movl	#_fswintr,a1@(PCB_ONFAULT)
1725	movsw	d0,a0@
1726	nop
1727	moveq	#0,d0
1728	jra	Lfsdone
1729
1730ALTENTRY(suibyte, _subyte)
1731ENTRY(subyte)
1732	movl	sp@(4),a0		| address to write
1733	movb	sp@(11),d0		| value to put there
1734	movl	_curpcb,a1		| current pcb
1735	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1736	movsb	d0,a0@			| do write to user space
1737	nop
1738	moveq	#0,d0			| indicate no fault
1739	jra	Lfsdone
1740
1741#if defined(LUNA2)
1742ENTRY(suline)
1743	movl	sp@(4),a0		| address to write
1744	movl	_curpcb,a1		| current pcb
1745	movl	#Lslerr,a1@(PCB_ONFAULT) | where to return to on a fault
1746	movl	sp@(8),a1		| address of line
1747	movl	a1@+,d0			| get lword
1748	movsl	d0,a0@+			| put lword
1749	nop				| sync
1750	movl	a1@+,d0			| get lword
1751	movsl	d0,a0@+			| put lword
1752	nop				| sync
1753	movl	a1@+,d0			| get lword
1754	movsl	d0,a0@+			| put lword
1755	nop				| sync
1756	movl	a1@+,d0			| get lword
1757	movsl	d0,a0@+			| put lword
1758	nop				| sync
1759	moveq	#0,d0			| indicate no fault
1760	jra	Lsldone
1761Lslerr:
1762	moveq	#-1,d0
1763Lsldone:
1764	movl	_curpcb,a1		| current pcb
1765	clrl	a1@(PCB_ONFAULT) 	| clear fault address
1766	rts
1767#endif
1768
1769/*
1770 * Invalidate entire TLB.
1771 */
1772ENTRY(TBIA)
1773__TBIA:
1774#if defined(LUNA2)
1775	cmpl	#-2,_mmutype		| 68040?
1776	jne	Lmotommu3		| no, skip
1777	.word	0xf518			| yes, pflusha
1778	rts
1779Lmotommu3:
1780#endif
1781	pflusha				| flush entire TLB
1782	movl	#DC_CLEAR,d0
1783	movc	d0,cacr			| invalidate on-chip d-cache
1784	rts
1785
1786/*
1787 * Invalidate any TLB entry for given VA (TB Invalidate Single)
1788 */
1789ENTRY(TBIS)
1790#ifdef DEBUG
1791	tstl	fulltflush		| being conservative?
1792	jne	__TBIA			| yes, flush entire TLB
1793#endif
1794#if defined(LUNA2)
1795	cmpl	#-2,_mmutype		| 68040?
1796	jne	Lmotommu4		| no, skip
1797	movl	sp@(4),a0
1798	movc	dfc,d1
1799	moveq	#1,d0			| user space
1800	movc	d0,dfc
1801	.word	0xf508			| pflush a0@
1802	moveq	#5,d0			| super space
1803	movc	d0,dfc
1804	.word	0xf508			| pflush a0@
1805	movc	d1,dfc
1806	rts
1807Lmotommu4:
1808#endif
1809	movl	sp@(4),a0		| get addr to flush
1810	pflush	#0,#0,a0@		| flush address from both sides
1811	movl	#DC_CLEAR,d0
1812	movc	d0,cacr			| invalidate on-chip data cache
1813	rts
1814
1815/*
1816 * Invalidate supervisor side of TLB
1817 */
1818ENTRY(TBIAS)
1819#ifdef DEBUG
1820	tstl	fulltflush		| being conservative?
1821	jne	__TBIA			| yes, flush everything
1822#endif
1823#if defined(LUNA2)
1824	cmpl	#-2,_mmutype		| 68040?
1825	jne	Lmotommu5		| no, skip
1826	.word	0xf518			| yes, pflusha (for now) XXX
1827	rts
1828Lmotommu5:
1829#endif
1830	pflush #4,#4			| flush supervisor TLB entries
1831	movl	#DC_CLEAR,d0
1832	movc	d0,cacr			| invalidate on-chip d-cache
1833	rts
1834
1835/*
1836 * Invalidate user side of TLB
1837 */
1838ENTRY(TBIAU)
1839#ifdef DEBUG
1840	tstl	fulltflush		| being conservative?
1841	jne	__TBIA			| yes, flush everything
1842#endif
1843#if defined(LUNA2)
1844	cmpl	#-2,_mmutype		| 68040?
1845	jne	Lmotommu6		| no, skip
1846	.word	0xf518			| yes, pflusha (for now) XXX
1847	rts
1848Lmotommu6:
1849#endif
1850	pflush	#0,#4			| flush user TLB entries
1851	movl	#DC_CLEAR,d0
1852	movc	d0,cacr			| invalidate on-chip d-cache
1853	rts
1854
1855/*
1856 * Invalidate instruction cache
1857 */
1858ENTRY(ICIA)
1859#if defined(LUNA2)
1860ENTRY(ICPA)
1861	cmpl	#-2,_mmutype		| 68040
1862	jne	Lmotommu7		| no, skip
1863	.word	0xf498			| cinva ic
1864	rts
1865Lmotommu7:
1866#endif
1867	movl	#IC_CLEAR,d0
1868	movc	d0,cacr			| invalidate i-cache
1869	rts
1870
1871/*
1872 * Invalidate data cache.
1873 * NOTE: we do not flush 68030 on-chip cache as there are no aliasing
1874 * problems with DC_WA.  The only cases we have to worry about are context
1875 * switch and TLB changes, both of which are handled "in-line" in resume
1876 * and TBI*.
1877 */
1878ENTRY(DCIA)
1879__DCIA:
1880#if defined(LUNA2)
1881	cmpl	#-2,_mmutype		| 68040
1882	jne	Lmotommu8		| no, skip
1883	/* XXX implement */
1884	rts
1885Lmotommu8:
1886#endif
1887	rts
1888
1889ENTRY(DCIS)
1890__DCIS:
1891#if defined(LUNA2)
1892	cmpl	#-2,_mmutype		| 68040
1893	jne	Lmotommu9		| no, skip
1894	/* XXX implement */
1895	rts
1896Lmotommu9:
1897#endif
1898	rts
1899
1900ENTRY(DCIU)
1901__DCIU:
1902#if defined(LUNA2)
1903	cmpl	#-2,_mmutype		| 68040
1904	jne	LmotommuA		| no, skip
1905	/* XXX implement */
1906	rts
1907LmotommuA:
1908#endif
1909	rts
1910
1911#if defined(LUNA2)
1912ENTRY(ICPL)
1913	movl	sp@(4),a0		| address
1914	.word	0xf488			| cinvl ic,a0@
1915	rts
1916ENTRY(ICPP)
1917	movl	sp@(4),a0		| address
1918	.word	0xf490			| cinvp ic,a0@
1919	rts
1920ENTRY(DCPL)
1921	movl	sp@(4),a0		| address
1922	.word	0xf448			| cinvl dc,a0@
1923	rts
1924ENTRY(DCPP)
1925	movl	sp@(4),a0		| address
1926	.word	0xf450			| cinvp dc,a0@
1927	rts
1928ENTRY(DCPA)
1929	.word	0xf458			| cinva dc
1930	rts
1931ENTRY(DCFL)
1932	movl	sp@(4),a0		| address
1933	.word	0xf468			| cpushl dc,a0@
1934	rts
1935ENTRY(DCFP)
1936	movl	sp@(4),a0		| address
1937	.word	0xf470			| cpushp dc,a0@
1938	rts
1939#endif
1940
1941ENTRY(PCIA)
1942#if defined(LUNA2)
1943ENTRY(DCFA)
1944	cmpl	#-2,_mmutype		| 68040
1945	jne	LmotommuB		| no, skip
1946	.word	0xf478			| cpusha dc
1947	rts
1948LmotommuB:
1949#endif
1950	movl	#DC_CLEAR,d0
1951	movc	d0,cacr			| invalidate on-chip d-cache
1952	rts
1953
1954#if 0 /****************************************************************/
1955/* external cache control */
1956ENTRY(ecacheon)
1957	rts
1958
1959ENTRY(ecacheoff)
1960	rts
1961#endif /****************************************************************/
1962
1963/*
1964 * Get callers current SP value.
1965 * Note that simply taking the address of a local variable in a C function
1966 * doesn't work because callee saved registers may be outside the stack frame
1967 * defined by A6 (e.g. GCC generated code).
1968 */
1969	.globl	_getsp
1970_getsp:
1971	movl	sp,d0			| get current SP
1972	addql	#4,d0			| compensate for return address
1973	rts
1974
1975	.globl	_getsfc, _getdfc
1976_getsfc:
1977	movc	sfc,d0
1978	rts
1979_getdfc:
1980	movc	dfc,d0
1981	rts
1982
1983/*
1984 * Load a new user segment table pointer.
1985 */
1986ENTRY(loadustp)
1987	movl	sp@(4),d0		| new USTP
1988	moveq	#PGSHIFT,d1
1989	lsll	d1,d0			| convert to addr
1990#if defined(LUNA2)
1991	cmpl	#-2,_mmutype		| 68040?
1992	jne	LmotommuC		| no, skip
1993	.long	0x4e7b0806		| movc d0,urp
1994	rts
1995LmotommuC:
1996#endif
1997	lea	_protorp,a0		| CRP prototype
1998	movl	d0,a0@(4)		| stash USTP
1999	pmove	a0@,crp			| load root pointer
2000	movl	#DC_CLEAR,d0
2001	movc	d0,cacr			| invalidate on-chip d-cache
2002	rts
2003
2004ENTRY(ploadw)
2005	movl	sp@(4),a0		| address to load
2006	ploadw	#1,a0@			| pre-load translation
2007	rts
2008
2009/*
2010 * Set processor priority level calls.  Most are implemented with
2011 * inline asm expansions.  However, spl0 requires special handling
2012 * as we need to check for our emulated software interrupts.
2013 */
2014
2015ENTRY(spl0)
2016	moveq	#0,d0
2017	movw	sr,d0			| get old SR for return
2018	movw	#PSL_LOWIPL,sr		| restore new SR
2019	tstb	_ssir			| software interrupt pending?
2020	jeq	Lspldone		| no, all done
2021	subql	#4,sp			| make room for RTE frame
2022	movl	sp@(4),sp@(2)		| position return address
2023	clrw	sp@(6)			| set frame type 0
2024	movw	#PSL_LOWIPL,sp@		| and new SR
2025	jra	Lgotsir			| go handle it
2026Lspldone:
2027	rts
2028
2029ENTRY(_insque)
2030	movw	sr,d0
2031	movw	#PSL_HIGHIPL,sr		| atomic
2032	movl	sp@(8),a0		| where to insert (after)
2033	movl	sp@(4),a1		| element to insert (e)
2034	movl	a0@,a1@			| e->next = after->next
2035	movl	a0,a1@(4)		| e->prev = after
2036	movl	a1,a0@			| after->next = e
2037	movl	a1@,a0
2038	movl	a1,a0@(4)		| e->next->prev = e
2039	movw	d0,sr
2040	rts
2041
2042ENTRY(_remque)
2043	movw	sr,d0
2044	movw	#PSL_HIGHIPL,sr		| atomic
2045	movl	sp@(4),a0		| element to remove (e)
2046	movl	a0@,a1
2047	movl	a0@(4),a0
2048	movl	a0,a1@(4)		| e->next->prev = e->prev
2049	movl	a1,a0@			| e->prev->next = e->next
2050	movw	d0,sr
2051	rts
2052
2053/*
2054 * bzero(addr, count)
2055 */
2056ALTENTRY(blkclr, _bzero)
2057ENTRY(bzero)
2058	movl	sp@(4),a0	| address
2059	movl	sp@(8),d0	| count
2060	jeq	Lbzdone		| if zero, nothing to do
2061	movl	a0,d1
2062	btst	#0,d1		| address odd?
2063	jeq	Lbzeven		| no, can copy words
2064	clrb	a0@+		| yes, zero byte to get to even boundary
2065	subql	#1,d0		| decrement count
2066	jeq	Lbzdone		| none left, all done
2067Lbzeven:
2068	movl	d0,d1
2069	andl	#31,d0
2070	lsrl	#5,d1		| convert count to 8*longword count
2071	jeq	Lbzbyte		| no such blocks, zero byte at a time
2072Lbzloop:
2073	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
2074	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
2075	subql	#1,d1		| one more block zeroed
2076	jne	Lbzloop		| more to go, do it
2077	tstl	d0		| partial block left?
2078	jeq	Lbzdone		| no, all done
2079Lbzbyte:
2080	clrb	a0@+
2081	subql	#1,d0		| one more byte cleared
2082	jne	Lbzbyte		| more to go, do it
2083Lbzdone:
2084	rts
2085
2086/*
2087 * strlen(str)
2088 */
2089ENTRY(strlen)
2090	moveq	#-1,d0
2091	movl	sp@(4),a0	| string
2092Lslloop:
2093	addql	#1,d0		| increment count
2094	tstb	a0@+		| null?
2095	jne	Lslloop		| no, keep going
2096	rts
2097
2098/*
2099 * bcmp(s1, s2, len)
2100 *
2101 * WARNING!  This guy only works with counts up to 64K
2102 */
2103ENTRY(bcmp)
2104	movl	sp@(4),a0		| string 1
2105	movl	sp@(8),a1		| string 2
2106	moveq	#0,d0
2107	movw	sp@(14),d0		| length
2108	jeq	Lcmpdone		| if zero, nothing to do
2109	subqw	#1,d0			| set up for DBcc loop
2110Lcmploop:
2111	cmpmb	a0@+,a1@+		| equal?
2112	dbne	d0,Lcmploop		| yes, keep going
2113	addqw	#1,d0			| +1 gives zero on match
2114Lcmpdone:
2115	rts
2116
2117/*
2118 * {ov}bcopy(from, to, len)
2119 *
2120 * Works for counts up to 128K.
2121 */
2122ALTENTRY(ovbcopy, _bcopy)
2123ENTRY(bcopy)
2124	movl	sp@(12),d0		| get count
2125	jeq	Lcpyexit		| if zero, return
2126	movl	sp@(4),a0		| src address
2127	movl	sp@(8),a1		| dest address
2128	cmpl	a1,a0			| src before dest?
2129	jlt	Lcpyback		| yes, copy backwards (avoids overlap)
2130	movl	a0,d1
2131	btst	#0,d1			| src address odd?
2132	jeq	Lcfeven			| no, go check dest
2133	movb	a0@+,a1@+		| yes, copy a byte
2134	subql	#1,d0			| update count
2135	jeq	Lcpyexit		| exit if done
2136Lcfeven:
2137	movl	a1,d1
2138	btst	#0,d1			| dest address odd?
2139	jne	Lcfbyte			| yes, must copy by bytes
2140	movl	d0,d1			| no, get count
2141	lsrl	#2,d1			| convert to longwords
2142	jeq	Lcfbyte			| no longwords, copy bytes
2143	subql	#1,d1			| set up for dbf
2144Lcflloop:
2145	movl	a0@+,a1@+		| copy longwords
2146	dbf	d1,Lcflloop		| til done
2147	andl	#3,d0			| get remaining count
2148	jeq	Lcpyexit		| done if none
2149Lcfbyte:
2150	subql	#1,d0			| set up for dbf
2151Lcfbloop:
2152	movb	a0@+,a1@+		| copy bytes
2153	dbf	d0,Lcfbloop		| til done
2154Lcpyexit:
2155	rts
2156Lcpyback:
2157	addl	d0,a0			| add count to src
2158	addl	d0,a1			| add count to dest
2159	movl	a0,d1
2160	btst	#0,d1			| src address odd?
2161	jeq	Lcbeven			| no, go check dest
2162	movb	a0@-,a1@-		| yes, copy a byte
2163	subql	#1,d0			| update count
2164	jeq	Lcpyexit		| exit if done
2165Lcbeven:
2166	movl	a1,d1
2167	btst	#0,d1			| dest address odd?
2168	jne	Lcbbyte			| yes, must copy by bytes
2169	movl	d0,d1			| no, get count
2170	lsrl	#2,d1			| convert to longwords
2171	jeq	Lcbbyte			| no longwords, copy bytes
2172	subql	#1,d1			| set up for dbf
2173Lcblloop:
2174	movl	a0@-,a1@-		| copy longwords
2175	dbf	d1,Lcblloop		| til done
2176	andl	#3,d0			| get remaining count
2177	jeq	Lcpyexit		| done if none
2178Lcbbyte:
2179	subql	#1,d0			| set up for dbf
2180Lcbbloop:
2181	movb	a0@-,a1@-		| copy bytes
2182	dbf	d0,Lcbbloop		| til done
2183	rts
2184
2185/*
2186 * Emulate fancy VAX string operations:
2187 *	scanc(count, startc, table, mask)
2188 *	skpc(mask, count, startc)
2189 *	locc(mask, count, startc)
2190 */
2191ENTRY(scanc)
2192	movl	sp@(4),d0	| get length
2193	jeq	Lscdone		| nothing to do, return
2194	movl	sp@(8),a0	| start of scan
2195	movl	sp@(12),a1	| table to compare with
2196	movb	sp@(19),d1	| and mask to use
2197	movw	d2,sp@-		| need a scratch register
2198	clrw	d2		| clear it out
2199	subqw	#1,d0		| adjust for dbra
2200Lscloop:
2201	movb	a0@+,d2		| get character
2202	movb	a1@(0,d2:w),d2	| get table entry
2203	andb	d1,d2		| mask it
2204	dbne	d0,Lscloop	| keep going til no more or non-zero
2205	addqw	#1,d0		| overshot by one
2206	movw	sp@+,d2		| restore scratch
2207Lscdone:
2208	rts
2209
2210ENTRY(skpc)
2211	movl	sp@(8),d0	| get length
2212	jeq	Lskdone		| nothing to do, return
2213	movb	sp@(7),d1	| mask to use
2214	movl	sp@(12),a0	| where to start
2215	subqw	#1,d0		| adjust for dbcc
2216Lskloop:
2217	cmpb	a0@+,d1		| compate with mask
2218	dbne	d0,Lskloop	| keep going til no more or zero
2219	addqw	#1,d0		| overshot by one
2220Lskdone:
2221	rts
2222
2223ENTRY(locc)
2224	movl	sp@(8),d0	| get length
2225	jeq	Llcdone		| nothing to do, return
2226	movb	sp@(7),d1	| mask to use
2227	movl	sp@(12),a0	| where to start
2228	subqw	#1,d0		| adjust for dbcc
2229Llcloop:
2230	cmpb	a0@+,d1		| compate with mask
2231	dbeq	d0,Llcloop	| keep going til no more or non-zero
2232	addqw	#1,d0		| overshot by one
2233Llcdone:
2234	rts
2235
2236/*
2237 * Emulate VAX FFS (find first set) instruction.
2238 */
2239ENTRY(ffs)
2240	moveq	#-1,d0
2241	movl	sp@(4),d1
2242	jeq	Lffsdone
2243Lffsloop:
2244	addql	#1,d0
2245	btst	d0,d1
2246	jeq	Lffsloop
2247Lffsdone:
2248	addql	#1,d0
2249	rts
2250
2251#ifdef FPCOPROC
2252/*
2253 * Save and restore 68881 state.
2254 * Pretty awful looking since our assembler does not
2255 * recognize FP mnemonics.
2256 */
2257ENTRY(m68881_save)
2258	movl	sp@(4),a0		| save area pointer
2259	fsave	a0@			| save state
2260	tstb	a0@			| null state frame?
2261	jeq	Lm68881sdone		| yes, all done
2262	fmovem fp0-fp7,a0@(216)		| save FP general registers
2263	fmovem fpcr/fpsr/fpi,a0@(312)	| save FP control registers
2264Lm68881sdone:
2265	rts
2266
2267ENTRY(m68881_restore)
2268	movl	sp@(4),a0		| save area pointer
2269	tstb	a0@			| null state frame?
2270	jeq	Lm68881rdone		| yes, easy
2271	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
2272	fmovem	a0@(216),fp0-fp7	| restore FP general registers
2273Lm68881rdone:
2274	frestore a0@			| restore state
2275	rts
2276
2277/* LUNA */
2278
2279	.globl	_fpp_svarea
2280
2281/* Fpp is MC68882 ? */
2282ENTRY(is_68882)
2283	frestore _fppnull	| initialize fpp
2284	movl	#2,d0
2285	fmovecr	#0,fp1
2286	fsinx	fp1,fp2
2287	lea	_fpp_svarea,a0	| save area
2288	movw	sr,d1		| save status reg.
2289	movw	#0x2700,sr	| mask intrrupt
2290	fsave	a0@		| save fpp context
2291	movw	d1,sr		| restore status reg.
2292	movl	a0@,d1
2293	andl	#0x00ff0000,d1  | check status field
2294	cmpl	#0x00180000,d1  | 68881(idle)?
2295	beq	_is81
2296	cmpl	#0x00b40000,d1	| 68881(busy)?
2297	beq	_is81
2298	cmpl	#0x00380000,d1	| 68882(idle)?
2299	beq	_is82
2300	cmpl	#0x00d40000,d1	| 68882(busy)?
2301	beq	_is82
2302	bra	_is82out	| default 68881
2303_is81:
2304	clrl	d0
2305	bra	_is82out
2306_is82:
2307	movl	#1,d0
2308_is82out:
2309	frestore a0@
2310	rts
2311
2312#ifdef	OLD_LUNA
2313/* We have fpp ? */
2314ENTRY(havefpp)
2315	movl	a2,sp@-
2316	clrl	d0
2317	movl	vb,a2
2318	movl	a2@(FLINE_VEC),a0	| save vectors
2319	movl	a2@(COPRO_VEC),a1
2320	movl	sp,d1
2321	movl	#_fpvec,a2@(FLINE_VEC)	| change vectors
2322	movl	#_fpvec,a2@(COPRO_VEC)
2323	fnop				| cause exception ?
2324	movl	#1,d0
2325_fpvec:	movl	a0,a2@(FLINE_VEC)	| restore vectors
2326	movl	a1,a2@(COPRO_VEC)
2327	movl	d1,sp
2328	movl	sp@+,a2
2329	rts
2330#endif
2331#endif
2332
2333/*
2334 * Handle the nitty-gritty of rebooting the machine.
2335 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
2336 * Note that we must be running in an address range that is mapped one-to-one
2337 * logical to physical so that the PC is still valid immediately after the MMU
2338 * is turned off.  We have conveniently mapped the last page of physical
2339 * memory this way.
2340 */
2341	.globl	_doboot
2342_doboot:
2343	movl	#0x41000004,a0
2344	movl	a0@,a1			| get PROM restart entry address
2345#if defined(LUNA2)
2346	cmpl	#-2,_mmutype		| 68040?
2347	jne	LmotommuF		| no, skip
2348
2349	movw	#PSL_HIGHIPL,sr		| no interrupts
2350
2351	movl	#0x41000000,a0
2352	movl	a0@,d0
2353	movc	d0,isp			| set ISP
2354
2355	.word	0xf4f8			| cpusha bc
2356	movl	#0,d0
2357	movc	d0,cacr			| caches off
2358	movql	#0,d0
2359	.long	0x4e7b0004		| movc d0,itt0
2360	.long	0x4e7b0005		| movc d0,itt1
2361	.long	0x4e7b0006		| movc d0,dtt0
2362	.long	0x4e7b0007		| movc d0,dtt1
2363
2364	.long	0x4e7b0003		| movc d0,tc
2365
2366	jmp	a1@			| goto REBOOT
2367LmotommuF:
2368#endif
2369	movl	#CACHE_OFF,d0
2370	movc	d0,cacr			| disable on-chip cache(s)
2371	movl	#_tcroff,a0		| value for pmove to TC (turn off MMU)
2372	pmove	a0@,tc			| disable MMU
2373	jmp	a1@			| goto REBOOT
2374
2375	.data
2376	.globl	_machineid,_mmutype
2377_machineid:
2378	.long	1		| default to LUNA-I
2379_mmutype:
2380	.long	-1		| default to 68030 PMMU
2381	.globl	_protorp,_protott0,_protott1
2382_protorp:
2383	.long	0,0		| prototype root pointer
2384_protott0:
2385	.long	0x403f8543	| tt0 (for LUNA1 kernel 0x40000000-0x7fffffff)
2386_protott1:
2387	.long	0x807F8543	| tt1 (for LUNA1 kernel 0x80000000-0xffffffff)
2388_mapping_tc:
2389	.long	0
2390	.globl	_cold
2391_cold:
2392	.long	1		| cold start flag
2393	.globl	_want_resched
2394_want_resched:
2395	.long	0
2396	.globl	_proc0paddr
2397_proc0paddr:
2398	.long	0		| KVA of proc0 u-area
2399
2400	.globl	_tcroff
2401_tcroff:
2402	.long	0		| TC reg. reset flag
2403
2404#ifdef FPCOPROC
2405	.globl	_fppnull
2406_fppnull:
2407	.long	0
2408#endif
2409	.globl	_clock_on
2410_clock_on:
2411	.long	0		| clock is enable ?
2412	.globl	_dipswitch
2413_dipswitch:
2414	.word	0		| dipsw(front panel) value
2415	.globl	_KernInter
2416_KernInter:			| Kernel InterFace Field
2417	.space	KIFF_SIZE
2418#ifdef DEBUG
2419	.globl	fulltflush, fullcflush
2420fulltflush:
2421	.long	0
2422fullcflush:
2423	.long	0
2424#endif
2425#ifdef HPFPLIB
2426/*
2427 * Undefined symbols from hpux_float.o:
2428 *
2429 * kdb_printf:	A kernel debugger print routine, we just use printf instead.
2430 * processor:	HP-UX equiv. of machineid, set to 3 if it is a 68040.
2431 * u:		Ye ole u-area.  The code wants to grab the first longword
2432 *		indirect off of that and clear the 0x40000 bit there.
2433 *		Oddly enough this was incorrect even in HP-UX!
2434 * runrun:	Old name for want_resched.
2435 */
2436	.globl	_kdb_printf,_processor,_u,_runrun
2437_kdb_printf:
2438	.long	_printf
2439_processor:
2440	.long	0
2441_u:
2442	.long	.+4
2443	.long	0
2444	.set	_runrun,_want_resched
2445#endif
2446/* interrupt counters */
2447	.globl	_intrcnt,_eintrcnt,_intrnames,_eintrnames
2448_intrnames:
2449	.asciz	"spur"
2450	.asciz	"lev1"
2451	.asciz	"lev2"
2452	.asciz	"lev3"
2453	.asciz	"lev4"
2454	.asciz	"clock"
2455	.asciz	"lev7"
2456	.asciz	"nmi"
2457_eintrnames:
2458	.even
2459_intrcnt:
2460	.long	0,0,0,0,0,0,0,0,0
2461_eintrcnt:
2462