xref: /original-bsd/sys/luna68k/luna68k/locore.s (revision 913acf41)
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	7.22 (Berkeley) 2/18/93
15 *
16 *	@(#)locore.s	8.3 (Berkeley) 09/23/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_exit'ed,
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	jbsr	_main			| call main()
914
915/* proc[1] == init now running here;
916 * create a null exception frame and return to user mode in icode
917 */
918#if defined(LUNA2)
919	cmpl	#-2,_mmutype		| 68040?
920	jne	Lnoflush		| no, skip
921	.word	0xf478			| cpusha dc
922	.word	0xf498			| cinva ic
923Lnoflush:
924#endif
925	clrw	sp@-			| vector offset/frame type
926	clrl	sp@-			| return to icode location 0
927	movw	#PSL_USER,sp@-		| in user mode
928	rte
929
930/*
931 * Signal "trampoline" code (18 bytes).  Invoked from RTE setup by sendsig().
932 *
933 * Stack looks like:
934 *
935 *	sp+0 ->	signal number
936 *	sp+4	signal specific code
937 *	sp+8	pointer to signal context frame (scp)
938 *	sp+12	address of handler
939 *	sp+16	saved hardware state
940 *			.
941 *			.
942 *	scp+0->	beginning of signal context frame
943 */
944	.globl	_sigcode, _esigcode, _sigcodetrap
945	.data
946_sigcode:
947	movl	sp@(12),a0		| signal handler addr	(4 bytes)
948	jsr	a0@			| call signal handler	(2 bytes)
949	addql	#4,sp			| pop signo		(2 bytes)
950_sigcodetrap:
951	trap	#1			| special syscall entry	(2 bytes)
952	movl	d0,sp@(4)		| save errno		(4 bytes)
953	moveq	#1,d0			| syscall == exit	(2 bytes)
954	trap	#0			| exit(errno)		(2 bytes)
955	.align	2
956_esigcode:
957
958/*
959 * Icode is copied out to process 1 to exec init.
960 * If the exec fails, process 1 exits.
961 */
962	.globl	_icode,_szicode
963	.text
964_icode:
965	clrl	sp@-
966	pea	pc@((argv-.)+2)
967	pea	pc@((init-.)+2)
968	clrl	sp@-
969	moveq	#SYS_execve,d0
970	trap	#0
971	moveq	#SYS_exit,d0
972	trap	#0
973init:
974	.asciz	"/sbin/init"
975	.even
976argv:
977	.long	init+6-_icode		| argv[0] = "init" ("/sbin/init" + 6)
978	.long	eicode-_icode		| argv[1] follows icode after copyout
979	.long	0
980eicode:
981
982_szicode:
983	.long	_szicode-_icode
984
985/*
986 * Primitives
987 */
988
989#ifdef __STDC__
990#define EXPORT(name)	.globl _ ## name; _ ## name:
991#else
992#define EXPORT(name)	.globl _/**/name; _/**/name:
993#endif
994#ifdef GPROF
995#if __GNUC__ >= 2
996#define	ENTRY(name) \
997	EXPORT(name) link a6,\#0; jbsr mcount; unlk a6
998#else
999#define	ENTRY(name) \
1000	EXPORT(name) link a6,#0; jbsr mcount; unlk a6
1001#endif
1002#define ALTENTRY(name, rname) \
1003	ENTRY(name); jra rname+12
1004#else
1005#define	ENTRY(name) \
1006	EXPORT(name)
1007#define ALTENTRY(name, rname) \
1008	ENTRY(name)
1009#endif
1010
1011/*
1012 * For gcc2
1013 */
1014ENTRY(__main)
1015	rts
1016
1017/*
1018 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
1019 *
1020 * Copy a null terminated string from the user address space into
1021 * the kernel address space.
1022 * NOTE: maxlength must be < 64K
1023 */
1024ENTRY(copyinstr)
1025	movl	_curpcb,a0		| current pcb
1026	movl	#Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults
1027	movl	sp@(4),a0		| a0 = fromaddr
1028	movl	sp@(8),a1		| a1 = toaddr
1029	moveq	#0,d0
1030	movw	sp@(14),d0		| d0 = maxlength
1031	jlt	Lcisflt1		| negative count, error
1032	jeq	Lcisdone		| zero count, all done
1033	subql	#1,d0			| set up for dbeq
1034Lcisloop:
1035	movsb	a0@+,d1			| grab a byte
1036	nop
1037	movb	d1,a1@+			| copy it
1038	dbeq	d0,Lcisloop		| if !null and more, continue
1039	jne	Lcisflt2		| ran out of room, error
1040	moveq	#0,d0			| got a null, all done
1041Lcisdone:
1042	tstl	sp@(16)			| return length desired?
1043	jeq	Lcisret			| no, just return
1044	subl	sp@(4),a0		| determine how much was copied
1045	movl	sp@(16),a1		| return location
1046	movl	a0,a1@			| stash it
1047Lcisret:
1048	movl	_curpcb,a0		| current pcb
1049	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
1050	rts
1051Lcisflt1:
1052	moveq	#EFAULT,d0		| copy fault
1053	jra	Lcisdone
1054Lcisflt2:
1055	moveq	#ENAMETOOLONG,d0	| ran out of space
1056	jra	Lcisdone
1057
1058/*
1059 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1060 *
1061 * Copy a null terminated string from the kernel
1062 * address space to the user address space.
1063 * NOTE: maxlength must be < 64K
1064 */
1065ENTRY(copyoutstr)
1066	movl	_curpcb,a0		| current pcb
1067	movl	#Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults
1068	movl	sp@(4),a0		| a0 = fromaddr
1069	movl	sp@(8),a1		| a1 = toaddr
1070	moveq	#0,d0
1071	movw	sp@(14),d0		| d0 = maxlength
1072	jlt	Lcosflt1		| negative count, error
1073	jeq	Lcosdone		| zero count, all done
1074	subql	#1,d0			| set up for dbeq
1075Lcosloop:
1076	movb	a0@+,d1			| grab a byte
1077	movsb	d1,a1@+			| copy it
1078	nop
1079	dbeq	d0,Lcosloop		| if !null and more, continue
1080	jne	Lcosflt2		| ran out of room, error
1081	moveq	#0,d0			| got a null, all done
1082Lcosdone:
1083	tstl	sp@(16)			| return length desired?
1084	jeq	Lcosret			| no, just return
1085	subl	sp@(4),a0		| determine how much was copied
1086	movl	sp@(16),a1		| return location
1087	movl	a0,a1@			| stash it
1088Lcosret:
1089	movl	_curpcb,a0		| current pcb
1090	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
1091	rts
1092Lcosflt1:
1093	moveq	#EFAULT,d0		| copy fault
1094	jra	Lcosdone
1095Lcosflt2:
1096	moveq	#ENAMETOOLONG,d0	| ran out of space
1097	jra	Lcosdone
1098
1099/*
1100 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1101 *
1102 * Copy a null terminated string from one point to another in
1103 * the kernel address space.
1104 * NOTE: maxlength must be < 64K
1105 */
1106ENTRY(copystr)
1107	movl	sp@(4),a0		| a0 = fromaddr
1108	movl	sp@(8),a1		| a1 = toaddr
1109	moveq	#0,d0
1110	movw	sp@(14),d0		| d0 = maxlength
1111	jlt	Lcsflt1			| negative count, error
1112	jeq	Lcsdone			| zero count, all done
1113	subql	#1,d0			| set up for dbeq
1114Lcsloop:
1115	movb	a0@+,a1@+		| copy a byte
1116	dbeq	d0,Lcsloop		| if !null and more, continue
1117	jne	Lcsflt2			| ran out of room, error
1118	moveq	#0,d0			| got a null, all done
1119Lcsdone:
1120	tstl	sp@(16)			| return length desired?
1121	jeq	Lcsret			| no, just return
1122	subl	sp@(4),a0		| determine how much was copied
1123	movl	sp@(16),a1		| return location
1124	movl	a0,a1@			| stash it
1125Lcsret:
1126	rts
1127Lcsflt1:
1128	moveq	#EFAULT,d0		| copy fault
1129	jra	Lcsdone
1130Lcsflt2:
1131	moveq	#ENAMETOOLONG,d0	| ran out of space
1132	jra	Lcsdone
1133
1134/*
1135 * Copyin(from_user, to_kernel, len)
1136 * Copyout(from_kernel, to_user, len)
1137 *
1138 * Copy specified amount of data between kernel and user space.
1139 *
1140 * XXX both use the DBcc instruction which has 16-bit limitation so only
1141 * 64k units can be copied, where "unit" is either a byte or a longword
1142 * depending on alignment.  To be safe, assume it can copy at most
1143 * 64k bytes.  Don't make MAXBSIZE or MAXPHYS larger than 64k without
1144 * fixing this code!
1145 */
1146ENTRY(copyin)
1147	movl	d2,sp@-			| scratch register
1148	movl	_curpcb,a0		| current pcb
1149	movl	#Lciflt,a0@(PCB_ONFAULT) | set up to catch faults
1150	movl	sp@(16),d2		| check count
1151	jlt	Lciflt			| negative, error
1152	jeq	Lcidone			| zero, done
1153	movl	sp@(8),a0		| src address
1154	movl	sp@(12),a1		| dest address
1155	movl	a0,d0
1156	btst	#0,d0			| src address odd?
1157	jeq	Lcieven			| no, go check dest
1158	movsb	a0@+,d1			| yes, get a byte
1159	nop
1160	movb	d1,a1@+			| put a byte
1161	subql	#1,d2			| adjust count
1162	jeq	Lcidone			| exit if done
1163Lcieven:
1164	movl	a1,d0
1165	btst	#0,d0			| dest address odd?
1166	jne	Lcibyte			| yes, must copy by bytes
1167	movl	d2,d0			| no, get count
1168	lsrl	#2,d0			| convert to longwords
1169	jeq	Lcibyte			| no longwords, copy bytes
1170	subql	#1,d0			| set up for dbf
1171Lcilloop:
1172	movsl	a0@+,d1			| get a long
1173	nop
1174	movl	d1,a1@+			| put a long
1175	dbf	d0,Lcilloop		| til done
1176	andl	#3,d2			| what remains
1177	jeq	Lcidone			| all done
1178Lcibyte:
1179	subql	#1,d2			| set up for dbf
1180Lcibloop:
1181	movsb	a0@+,d1			| get a byte
1182	nop
1183	movb	d1,a1@+			| put a byte
1184	dbf	d2,Lcibloop		| til done
1185Lcidone:
1186	moveq	#0,d0			| success
1187Lciexit:
1188	movl	_curpcb,a0		| current pcb
1189	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1190	movl	sp@+,d2			| restore scratch reg
1191	rts
1192Lciflt:
1193	moveq	#EFAULT,d0		| got a fault
1194	jra	Lciexit
1195
1196ENTRY(copyout)
1197	movl	d2,sp@-			| scratch register
1198	movl	_curpcb,a0		| current pcb
1199	movl	#Lcoflt,a0@(PCB_ONFAULT) | catch faults
1200	movl	sp@(16),d2		| check count
1201	jlt	Lcoflt			| negative, error
1202	jeq	Lcodone			| zero, done
1203	movl	sp@(8),a0		| src address
1204	movl	sp@(12),a1		| dest address
1205	movl	a0,d0
1206	btst	#0,d0			| src address odd?
1207	jeq	Lcoeven			| no, go check dest
1208	movb	a0@+,d1			| yes, get a byte
1209	movsb	d1,a1@+			| put a byte
1210	nop
1211	subql	#1,d2			| adjust count
1212	jeq	Lcodone			| exit if done
1213Lcoeven:
1214	movl	a1,d0
1215	btst	#0,d0			| dest address odd?
1216	jne	Lcobyte			| yes, must copy by bytes
1217	movl	d2,d0			| no, get count
1218	lsrl	#2,d0			| convert to longwords
1219	jeq	Lcobyte			| no longwords, copy bytes
1220	subql	#1,d0			| set up for dbf
1221Lcolloop:
1222	movl	a0@+,d1			| get a long
1223	movsl	d1,a1@+			| put a long
1224	nop
1225	dbf	d0,Lcolloop		| til done
1226	andl	#3,d2			| what remains
1227	jeq	Lcodone			| all done
1228Lcobyte:
1229	subql	#1,d2			| set up for dbf
1230Lcobloop:
1231	movb	a0@+,d1			| get a byte
1232	movsb	d1,a1@+			| put a byte
1233	nop
1234	dbf	d2,Lcobloop		| til done
1235Lcodone:
1236	moveq	#0,d0			| success
1237Lcoexit:
1238	movl	_curpcb,a0		| current pcb
1239	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1240	movl	sp@+,d2			| restore scratch reg
1241	rts
1242Lcoflt:
1243	moveq	#EFAULT,d0		| got a fault
1244	jra	Lcoexit
1245
1246/*
1247 * non-local gotos
1248 */
1249ENTRY(setjmp)
1250	movl	sp@(4),a0	| savearea pointer
1251	moveml	#0xFCFC,a0@	| save d2-d7/a2-a7
1252	movl	sp@,a0@(48)	| and return address
1253	moveq	#0,d0		| return 0
1254	rts
1255
1256ENTRY(longjmp)
1257	movl	sp@(4),a0
1258	moveml	a0@+,#0xFCFC
1259	movl	a0@,sp@
1260	moveq	#1,d0
1261	rts
1262
1263/*
1264 * The following primitives manipulate the run queues.  _whichqs tells which
1265 * of the 32 queues _qs have processes in them.  Setrunqueue puts processes
1266 * into queues, Remrq removes them from queues.  The running process is on
1267 * no queue, other processes are on a queue related to p->p_priority, divided
1268 * by 4 actually to shrink the 0-127 range of priorities into the 32 available
1269 * queues.
1270 */
1271	.globl	_whichqs,_qs,_cnt,_panic
1272	.globl	_curproc,_want_resched
1273
1274/*
1275 * Setrunqueue(p)
1276 *
1277 * Call should be made at spl6(), and p->p_stat should be SRUN
1278 */
1279ENTRY(setrunqueue)
1280	movl	sp@(4),a0
1281	tstl	a0@(P_BACK)
1282	jeq	Lset1
1283	movl	#Lset2,sp@-
1284	jbsr	_panic
1285Lset1:
1286	clrl	d0
1287	movb	a0@(P_PRIORITY),d0
1288	lsrb	#2,d0
1289	movl	_whichqs,d1
1290	bset	d0,d1
1291	movl	d1,_whichqs
1292	lslb	#3,d0
1293	addl	#_qs,d0
1294	movl	d0,a0@(P_FORW)
1295	movl	d0,a1
1296	movl	a1@(P_BACK),a0@(P_BACK)
1297	movl	a0,a1@(P_BACK)
1298	movl	a0@(P_BACK),a1
1299	movl	a0,a1@(P_FORW)
1300	rts
1301
1302Lset2:
1303	.asciz	"setrunqueue"
1304	.even
1305
1306/*
1307 * Remrq(p)
1308 *
1309 * Call should be made at spl6().
1310 */
1311ENTRY(remrq)
1312	movl	sp@(4),a0
1313	clrl	d0
1314	movb	a0@(P_PRIORITY),d0
1315	lsrb	#2,d0
1316	movl	_whichqs,d1
1317	bclr	d0,d1
1318	jne	Lrem1
1319	movl	#Lrem3,sp@-
1320	jbsr	_panic
1321Lrem1:
1322	movl	d1,_whichqs
1323	movl	a0@(P_FORW),a1
1324	movl	a0@(P_BACK),a1@(P_BACK)
1325	movl	a0@(P_BACK),a1
1326	movl	a0@(P_FORW),a1@(P_FORW)
1327	movl	#_qs,a1
1328	movl	d0,d1
1329	lslb	#3,d1
1330	addl	d1,a1
1331	cmpl	a1@(P_FORW),a1
1332	jeq	Lrem2
1333	movl	_whichqs,d1
1334	bset	d0,d1
1335	movl	d1,_whichqs
1336Lrem2:
1337	clrl	a0@(P_BACK)
1338	rts
1339
1340Lrem3:
1341	.asciz	"remrq"
1342Lsw0:
1343	.asciz	"switch"
1344	.even
1345
1346	.globl	_curpcb
1347	.globl	_masterpaddr	| XXX compatibility (debuggers)
1348	.data
1349_masterpaddr:			| XXX compatibility (debuggers)
1350_curpcb:
1351	.long	0
1352mdpflag:
1353	.byte	0		| copy of proc md_flags low byte
1354	.align	2
1355	.comm	nullpcb,SIZEOF_PCB
1356	.text
1357
1358/*
1359 * At exit of a process, do a switch for the last time.
1360 * The mapping of the pcb at p->p_addr has already been deleted,
1361 * and the memory for the pcb+stack has been freed.
1362 * The ipl is high enough to prevent the memory from being reallocated.
1363 */
1364ENTRY(switch_exit)
1365	movl	#nullpcb,_curpcb	| save state into garbage pcb
1366	lea	tmpstk,sp		| goto a tmp stack
1367	jra	_cpu_switch
1368
1369/*
1370 * When no processes are on the runq, Swtch branches to idle
1371 * to wait for something to come ready.
1372 */
1373	.globl	idle
1374Lidle:
1375	stop	#PSL_LOWIPL
1376idle:
1377	movw	#PSL_HIGHIPL,sr
1378	tstl	_whichqs
1379	jeq	Lidle
1380	movw	#PSL_LOWIPL,sr
1381	jra	Lsw1
1382
1383Lbadsw:
1384	movl	#Lsw0,sp@-
1385	jbsr	_panic
1386	/*NOTREACHED*/
1387
1388/*
1389 * cpu_switch()
1390 *
1391 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
1392 * entire ATC.  The effort involved in selective flushing may not be
1393 * worth it, maybe we should just flush the whole thing?
1394 *
1395 * NOTE 2: With the new VM layout we now no longer know if an inactive
1396 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1397 * bit).  For now, we just always flush the full ATC.
1398 */
1399ENTRY(cpu_switch)
1400	movl	_curpcb,a0		| current pcb
1401	movw	sr,a0@(PCB_PS)		| save sr before changing ipl
1402#ifdef notyet
1403	movl	_curproc,sp@-		| remember last proc running
1404#endif
1405	clrl	_curproc
1406	addql	#1,_cnt+V_SWTCH
1407
1408Lsw1:
1409	/*
1410	 * Find the highest-priority queue that isn't empty,
1411	 * then take the first proc from that queue.
1412	 */
1413	clrl	d0
1414	lea	_whichqs,a0
1415	movl	a0@,d1
1416Lswchk:
1417	btst	d0,d1
1418	jne	Lswfnd
1419	addqb	#1,d0
1420	cmpb	#32,d0
1421	jne	Lswchk
1422	jra	idle
1423Lswfnd:
1424	movw	#PSL_HIGHIPL,sr		| lock out interrupts
1425	movl	a0@,d1			| and check again...
1426	bclr	d0,d1
1427	jeq	Lsw1			| proc moved, rescan
1428	movl	d1,a0@			| update whichqs
1429	moveq	#1,d1			| double check for higher priority
1430	lsll	d0,d1			| process (which may have snuck in
1431	subql	#1,d1			| while we were finding this one)
1432	andl	a0@,d1
1433	jeq	Lswok			| no one got in, continue
1434	movl	a0@,d1
1435	bset	d0,d1			| otherwise put this one back
1436	movl	d1,a0@
1437	jra	Lsw1			| and rescan
1438Lswok:
1439	movl	d0,d1
1440	lslb	#3,d1			| convert queue number to index
1441	addl	#_qs,d1			| locate queue (q)
1442	movl	d1,a1
1443	cmpl	a1@(P_FORW),a1		| anyone on queue?
1444	jeq	Lbadsw			| no, panic
1445	movl	a1@(P_FORW),a0		| p = q->p_forw
1446	movl	a0@(P_FORW),a1@(P_FORW)	| q->p_forw = p->p_forw
1447	movl	a0@(P_FORW),a1		| q = p->p_forw
1448	movl	a0@(P_BACK),a1@(P_BACK)	| q->p_back = p->p_back
1449	cmpl	a0@(P_FORW),d1		| anyone left on queue?
1450	jeq	Lsw2			| no, skip
1451	movl	_whichqs,d1
1452	bset	d0,d1			| yes, reset bit
1453	movl	d1,_whichqs
1454Lsw2:
1455	movl	a0,_curproc
1456	clrl	_want_resched
1457#ifdef notyet
1458	movl	sp@+,a1
1459	cmpl	a0,a1			| switching to same proc?
1460	jeq	Lswdone			| yes, skip save and restore
1461#endif
1462	/*
1463	 * Save state of previous process in its pcb.
1464	 */
1465	movl	_curpcb,a1
1466	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1467	movl	usp,a2			| grab USP (a2 has been saved)
1468	movl	a2,a1@(PCB_USP)		| and save it
1469#ifdef FPCOPROC
1470	lea	a1@(PCB_FPCTX),a2	| pointer to FP save area
1471	fsave	a2@			| save FP state
1472	tstb	a2@			| null state frame?
1473	jeq	Lswnofpsave		| yes, all done
1474	fmovem	fp0-fp7,a2@(216)	| save FP general registers
1475	fmovem	fpcr/fpsr/fpi,a2@(312)	| save FP control registers
1476Lswnofpsave:
1477#endif
1478
1479#ifdef DIAGNOSTIC
1480	tstl	a0@(P_WCHAN)
1481	jne	Lbadsw
1482	cmpb	#SRUN,a0@(P_STAT)
1483	jne	Lbadsw
1484#endif
1485	clrl	a0@(P_BACK)		| clear back link
1486	movb	a0@(P_MDFLAG+3),mdpflag	| low byte of p_md.md_flags
1487	movl	a0@(P_ADDR),a1		| get p_addr
1488	movl	a1,_curpcb
1489
1490	/* see if pmap_activate needs to be called; should remove this */
1491	movl	a0@(P_VMSPACE),a0	| vmspace = p->p_vmspace
1492#ifdef DIAGNOSTIC
1493	tstl	a0			| map == VM_MAP_NULL?
1494	jeq	Lbadsw			| panic
1495#endif
1496	lea	a0@(VM_PMAP),a0		| pmap = &vmspace.vm_pmap
1497	tstl	a0@(PM_STCHG)		| pmap->st_changed?
1498	jeq	Lswnochg		| no, skip
1499	pea	a1@			| push pcb (at p_addr)
1500	pea	a0@			| push pmap
1501	jbsr	_pmap_activate		| pmap_activate(pmap, pcb)
1502	addql	#8,sp
1503	movl	_curpcb,a1		| restore p_addr
1504Lswnochg:
1505
1506	movl	#PGSHIFT,d1
1507	movl	a1,d0
1508	lsrl	d1,d0			| convert p_addr to page number
1509	lsll	#2,d0			| and now to Sysmap offset
1510	addl	_Sysmap,d0		| add Sysmap base to get PTE addr
1511#ifdef notdef
1512	movw	#PSL_HIGHIPL,sr		| go crit while changing PTEs
1513#endif
1514	lea	tmpstk,sp		| now goto a tmp stack for NMI
1515	movl	d0,a0			| address of new context
1516	movl	_Umap,a2		| address of PTEs for kstack
1517	moveq	#UPAGES-1,d0		| sizeof kstack
1518Lres1:
1519	movl	a0@+,d1			| get PTE
1520	andl	#~PG_PROT,d1		| mask out old protection
1521	orl	#PG_RW+PG_V,d1		| ensure valid and writable
1522	movl	d1,a2@+			| load it up
1523	dbf	d0,Lres1		| til done
1524#if defined(LUNA2)
1525	cmpl	#-2,_mmutype		| 68040?
1526	jne	Lres1a			| no, skip
1527	.word	0xf518			| yes, pflusha
1528	movl	a1@(PCB_USTP),d0	| get USTP
1529	moveq	#PGSHIFT,d1
1530	lsll	d1,d0			| convert to addr
1531	.long	0x4e7b0806		| movc d0,urp
1532	jra	Lcxswdone
1533Lres1a:
1534#endif
1535	movl	#CACHE_CLR,d0
1536	movc	d0,cacr			| invalidate cache(s)
1537	pflusha				| flush entire TLB
1538	movl	a1@(PCB_USTP),d0	| get USTP
1539	moveq	#PGSHIFT,d1
1540	lsll	d1,d0			| convert to addr
1541	lea	_protorp,a0		| CRP prototype
1542	movl	d0,a0@(4)		| stash USTP
1543	pmove	a0@,crp			| load new user root pointer
1544Lcxswdone:
1545	moveml	a1@(PCB_REGS),#0xFCFC	| and registers
1546	movl	a1@(PCB_USP),a0
1547	movl	a0,usp			| and USP
1548#ifdef FPCOPROC
1549	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1550	tstb	a0@			| null state frame?
1551	jeq	Lresfprest		| yes, easy
1552#if defined(LUNA2)
1553	cmpl	#-2,_mmutype		| 68040?
1554	jne	Lresnot040		| no, skip
1555	clrl	sp@-			| yes...
1556	frestore sp@+			| ...magic!
1557Lresnot040:
1558#endif
1559	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
1560	fmovem	a0@(216),fp0-fp7	| restore FP general registers
1561Lresfprest:
1562	frestore a0@			| restore state
1563#endif
1564	movw	a1@(PCB_PS),sr		| no, restore PS
1565	moveq	#1,d0			| return 1 (for alternate returns)
1566	rts
1567
1568/*
1569 * savectx(pcb, altreturn)
1570 * Update pcb, saving current processor state and arranging
1571 * for alternate return ala longjmp in switch if altreturn is true.
1572 */
1573ENTRY(savectx)
1574	movl	sp@(4),a1
1575	movw	sr,a1@(PCB_PS)
1576	movl	usp,a0			| grab USP
1577	movl	a0,a1@(PCB_USP)		| and save it
1578	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1579#ifdef FPCOPROC
1580	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1581	fsave	a0@			| save FP state
1582	tstb	a0@			| null state frame?
1583	jeq	Lsvnofpsave		| yes, all done
1584	fmovem	fp0-fp7,a0@(216)	| save FP general registers
1585	fmovem	fpcr/fpsr/fpi,a0@(312)	| save FP control registers
1586Lsvnofpsave:
1587#endif
1588	tstl	sp@(8)			| altreturn?
1589	jeq	Lsavedone
1590	movl	sp,d0			| relocate current sp relative to a1
1591	subl	#_kstack,d0		|   (sp is relative to kstack):
1592	addl	d0,a1			|   a1 += sp - kstack;
1593	movl	sp@,a1@			| write return pc at (relocated) sp@
1594Lsavedone:
1595	moveq	#0,d0			| return 0
1596	rts
1597
1598/*
1599 * {fu,su},{byte,sword,word}
1600 */
1601ALTENTRY(fuiword, _fuword)
1602ENTRY(fuword)
1603	movl	sp@(4),a0		| address to read
1604	movl	_curpcb,a1		| current pcb
1605	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1606	movsl	a0@,d0			| do read from user space
1607	nop
1608	jra	Lfsdone
1609
1610ENTRY(fusword)
1611	movl	sp@(4),a0
1612	movl	_curpcb,a1		| current pcb
1613	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1614	moveq	#0,d0
1615	movsw	a0@,d0			| do read from user space
1616	nop
1617	jra	Lfsdone
1618
1619/* Just like fusword, but tells trap code not to page in. */
1620ENTRY(fuswintr)
1621	movl	sp@(4),a0
1622	movl	_curpcb,a1
1623	movl	#_fswintr,a1@(PCB_ONFAULT)
1624	moveq	#0,d0
1625	movsw	a0@,d0
1626	nop
1627	jra	Lfsdone
1628
1629ALTENTRY(fuibyte, _fubyte)
1630ENTRY(fubyte)
1631	movl	sp@(4),a0		| address to read
1632	movl	_curpcb,a1		| current pcb
1633	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1634	moveq	#0,d0
1635	movsb	a0@,d0			| do read from user space
1636	nop
1637	jra	Lfsdone
1638
1639Lfserr:
1640	moveq	#-1,d0			| error indicator
1641Lfsdone:
1642	clrl	a1@(PCB_ONFAULT) 	| clear fault address
1643	rts
1644
1645/* Just like Lfserr, but the address is different (& exported). */
1646	.globl	_fswintr
1647_fswintr:
1648	moveq	#-1,d0
1649	jra	Lfsdone
1650
1651
1652/*
1653 * Write a longword in user instruction space.
1654 * Largely the same as suword but with a final i-cache purge on those
1655 * machines with split caches.
1656 */
1657ENTRY(suiword)
1658	movl	sp@(4),a0		| address to write
1659	movl	sp@(8),d0		| value to put there
1660	movl	_curpcb,a1		| current pcb
1661	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1662	movsl	d0,a0@			| do write to user space
1663	nop
1664	moveq	#0,d0			| indicate no fault
1665#if defined(LUNA2)
1666	cmpl	#-2,_mmutype		| 68040?
1667	jne	Lsuicpurge		| no, skip
1668	.word	0xf498			| cinva ic (XXX overkill)
1669	jra	Lfsdone
1670Lsuicpurge:
1671#endif
1672	movl	#IC_CLEAR,d1
1673	movc	d1,cacr			| invalidate i-cache
1674	jra	Lfsdone
1675
1676ENTRY(suword)
1677	movl	sp@(4),a0		| address to write
1678	movl	sp@(8),d0		| value to put there
1679	movl	_curpcb,a1		| current pcb
1680	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1681	movsl	d0,a0@			| do write to user space
1682	nop
1683	moveq	#0,d0			| indicate no fault
1684	jra	Lfsdone
1685
1686ENTRY(susword)
1687	movl	sp@(4),a0		| address to write
1688	movw	sp@(10),d0		| value to put there
1689	movl	_curpcb,a1		| current pcb
1690	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1691	movsw	d0,a0@			| do write to user space
1692	nop
1693	moveq	#0,d0			| indicate no fault
1694	jra	Lfsdone
1695
1696ENTRY(suswintr)
1697	movl	sp@(4),a0
1698	movw	sp@(10),d0
1699	movl	_curpcb,a1
1700	movl	#_fswintr,a1@(PCB_ONFAULT)
1701	movsw	d0,a0@
1702	nop
1703	moveq	#0,d0
1704	jra	Lfsdone
1705
1706ALTENTRY(suibyte, _subyte)
1707ENTRY(subyte)
1708	movl	sp@(4),a0		| address to write
1709	movb	sp@(11),d0		| value to put there
1710	movl	_curpcb,a1		| current pcb
1711	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1712	movsb	d0,a0@			| do write to user space
1713	nop
1714	moveq	#0,d0			| indicate no fault
1715	jra	Lfsdone
1716
1717#if defined(LUNA2)
1718ENTRY(suline)
1719	movl	sp@(4),a0		| address to write
1720	movl	_curpcb,a1		| current pcb
1721	movl	#Lslerr,a1@(PCB_ONFAULT) | where to return to on a fault
1722	movl	sp@(8),a1		| address of line
1723	movl	a1@+,d0			| get lword
1724	movsl	d0,a0@+			| put lword
1725	nop				| sync
1726	movl	a1@+,d0			| get lword
1727	movsl	d0,a0@+			| put lword
1728	nop				| sync
1729	movl	a1@+,d0			| get lword
1730	movsl	d0,a0@+			| put lword
1731	nop				| sync
1732	movl	a1@+,d0			| get lword
1733	movsl	d0,a0@+			| put lword
1734	nop				| sync
1735	moveq	#0,d0			| indicate no fault
1736	jra	Lsldone
1737Lslerr:
1738	moveq	#-1,d0
1739Lsldone:
1740	movl	_curpcb,a1		| current pcb
1741	clrl	a1@(PCB_ONFAULT) 	| clear fault address
1742	rts
1743#endif
1744
1745/*
1746 * Invalidate entire TLB.
1747 */
1748ENTRY(TBIA)
1749__TBIA:
1750#if defined(LUNA2)
1751	cmpl	#-2,_mmutype		| 68040?
1752	jne	Lmotommu3		| no, skip
1753	.word	0xf518			| yes, pflusha
1754	rts
1755Lmotommu3:
1756#endif
1757	pflusha				| flush entire TLB
1758	movl	#DC_CLEAR,d0
1759	movc	d0,cacr			| invalidate on-chip d-cache
1760	rts
1761
1762/*
1763 * Invalidate any TLB entry for given VA (TB Invalidate Single)
1764 */
1765ENTRY(TBIS)
1766#ifdef DEBUG
1767	tstl	fulltflush		| being conservative?
1768	jne	__TBIA			| yes, flush entire TLB
1769#endif
1770#if defined(LUNA2)
1771	cmpl	#-2,_mmutype		| 68040?
1772	jne	Lmotommu4		| no, skip
1773	movl	sp@(4),a0
1774	movc	dfc,d1
1775	moveq	#1,d0			| user space
1776	movc	d0,dfc
1777	.word	0xf508			| pflush a0@
1778	moveq	#5,d0			| super space
1779	movc	d0,dfc
1780	.word	0xf508			| pflush a0@
1781	movc	d1,dfc
1782	rts
1783Lmotommu4:
1784#endif
1785
1786	movl	sp@(4),a0		| get addr to flush
1787	pflush	#0,#0,a0@		| flush address from both sides
1788	movl	#DC_CLEAR,d0
1789	movc	d0,cacr			| invalidate on-chip data cache
1790	rts
1791
1792/*
1793 * Invalidate supervisor side of TLB
1794 */
1795ENTRY(TBIAS)
1796#ifdef DEBUG
1797	tstl	fulltflush		| being conservative?
1798	jne	__TBIA			| yes, flush everything
1799#endif
1800#if defined(LUNA2)
1801	cmpl	#-2,_mmutype		| 68040?
1802	jne	Lmotommu5		| no, skip
1803	.word	0xf518			| yes, pflusha (for now) XXX
1804	rts
1805Lmotommu5:
1806#endif
1807	pflush #4,#4			| flush supervisor TLB entries
1808	movl	#DC_CLEAR,d0
1809	movc	d0,cacr			| invalidate on-chip d-cache
1810	rts
1811
1812/*
1813 * Invalidate user side of TLB
1814 */
1815ENTRY(TBIAU)
1816#ifdef DEBUG
1817	tstl	fulltflush		| being conservative?
1818	jne	__TBIA			| yes, flush everything
1819#endif
1820#if defined(LUNA2)
1821	cmpl	#-2,_mmutype		| 68040?
1822	jne	Lmotommu6		| no, skip
1823	.word	0xf518			| yes, pflusha (for now) XXX
1824	rts
1825Lmotommu6:
1826#endif
1827	pflush	#0,#4			| flush user TLB entries
1828	movl	#DC_CLEAR,d0
1829	movc	d0,cacr			| invalidate on-chip d-cache
1830	rts
1831
1832/*
1833 * Invalidate instruction cache
1834 */
1835ENTRY(ICIA)
1836#if defined(LUNA2)
1837ENTRY(ICPA)
1838	cmpl	#-2,_mmutype		| 68040
1839	jne	Lmotommu7		| no, skip
1840	.word	0xf498			| cinva ic
1841	rts
1842Lmotommu7:
1843#endif
1844	movl	#IC_CLEAR,d0
1845	movc	d0,cacr			| invalidate i-cache
1846	rts
1847
1848/*
1849 * Invalidate data cache.
1850 * NOTE: we do not flush 68030 on-chip cache as there are no aliasing
1851 * problems with DC_WA.  The only cases we have to worry about are context
1852 * switch and TLB changes, both of which are handled "in-line" in resume
1853 * and TBI*.
1854 */
1855ENTRY(DCIA)
1856__DCIA:
1857#if defined(LUNA2)
1858	cmpl	#-2,_mmutype		| 68040
1859	jne	Lmotommu8		| no, skip
1860	/* XXX implement */
1861	rts
1862Lmotommu8:
1863#endif
1864	rts
1865
1866ENTRY(DCIS)
1867__DCIS:
1868#if defined(LUNA2)
1869	cmpl	#-2,_mmutype		| 68040
1870	jne	Lmotommu9		| no, skip
1871	/* XXX implement */
1872	rts
1873Lmotommu9:
1874#endif
1875	rts
1876
1877ENTRY(DCIU)
1878__DCIU:
1879#if defined(LUNA2)
1880	cmpl	#-2,_mmutype		| 68040
1881	jne	LmotommuA		| no, skip
1882	/* XXX implement */
1883	rts
1884LmotommuA:
1885#endif
1886	rts
1887
1888#if defined(LUNA2)
1889ENTRY(ICPL)
1890	movl	sp@(4),a0		| address
1891	.word	0xf488			| cinvl ic,a0@
1892	rts
1893ENTRY(ICPP)
1894	movl	sp@(4),a0		| address
1895	.word	0xf490			| cinvp ic,a0@
1896	rts
1897ENTRY(DCPL)
1898	movl	sp@(4),a0		| address
1899	.word	0xf448			| cinvl dc,a0@
1900	rts
1901ENTRY(DCPP)
1902	movl	sp@(4),a0		| address
1903	.word	0xf450			| cinvp dc,a0@
1904	rts
1905ENTRY(DCPA)
1906	.word	0xf458			| cinva dc
1907	rts
1908ENTRY(DCFL)
1909	movl	sp@(4),a0		| address
1910	.word	0xf468			| cpushl dc,a0@
1911	rts
1912ENTRY(DCFP)
1913	movl	sp@(4),a0		| address
1914	.word	0xf470			| cpushp dc,a0@
1915	rts
1916#endif
1917
1918ENTRY(PCIA)
1919#if defined(LUNA2)
1920ENTRY(DCFA)
1921	cmpl	#-2,_mmutype		| 68040
1922	jne	LmotommuB		| no, skip
1923	.word	0xf478			| cpusha dc
1924	rts
1925LmotommuB:
1926#endif
1927	movl	#DC_CLEAR,d0
1928	movc	d0,cacr			| invalidate on-chip d-cache
1929	rts
1930
1931#if 0 /****************************************************************/
1932/* external cache control */
1933ENTRY(ecacheon)
1934	rts
1935
1936ENTRY(ecacheoff)
1937	rts
1938#endif /****************************************************************/
1939
1940/*
1941 * Get callers current SP value.
1942 * Note that simply taking the address of a local variable in a C function
1943
1944 * doesn't work because callee saved registers may be outside the stack frame
1945 * defined by A6 (e.g. GCC generated code).
1946 */
1947	.globl	_getsp
1948_getsp:
1949	movl	sp,d0			| get current SP
1950	addql	#4,d0			| compensate for return address
1951	rts
1952
1953	.globl	_getsfc, _getdfc
1954_getsfc:
1955	movc	sfc,d0
1956	rts
1957_getdfc:
1958	movc	dfc,d0
1959	rts
1960
1961/*
1962 * Load a new user segment table pointer.
1963 */
1964ENTRY(loadustp)
1965	movl	sp@(4),d0		| new USTP
1966	moveq	#PGSHIFT,d1
1967	lsll	d1,d0			| convert to addr
1968#if defined(LUNA2)
1969	cmpl	#-2,_mmutype		| 68040?
1970	jne	LmotommuC		| no, skip
1971	.long	0x4e7b0806		| movc d0,urp
1972	rts
1973LmotommuC:
1974#endif
1975	lea	_protorp,a0		| CRP prototype
1976	movl	d0,a0@(4)		| stash USTP
1977	pmove	a0@,crp			| load root pointer
1978	movl	#DC_CLEAR,d0
1979	movc	d0,cacr			| invalidate on-chip d-cache
1980	rts
1981
1982ENTRY(ploadw)
1983	movl	sp@(4),a0		| address to load
1984	ploadw	#1,a0@			| pre-load translation
1985	rts
1986
1987/*
1988 * Set processor priority level calls.  Most are implemented with
1989 * inline asm expansions.  However, spl0 requires special handling
1990 * as we need to check for our emulated software interrupts.
1991 */
1992
1993ENTRY(spl0)
1994	moveq	#0,d0
1995	movw	sr,d0			| get old SR for return
1996	movw	#PSL_LOWIPL,sr		| restore new SR
1997	tstb	_ssir			| software interrupt pending?
1998	jeq	Lspldone		| no, all done
1999	subql	#4,sp			| make room for RTE frame
2000	movl	sp@(4),sp@(2)		| position return address
2001	clrw	sp@(6)			| set frame type 0
2002	movw	#PSL_LOWIPL,sp@		| and new SR
2003	jra	Lgotsir			| go handle it
2004Lspldone:
2005	rts
2006
2007ENTRY(_insque)
2008	movw	sr,d0
2009	movw	#PSL_HIGHIPL,sr		| atomic
2010	movl	sp@(8),a0		| where to insert (after)
2011	movl	sp@(4),a1		| element to insert (e)
2012	movl	a0@,a1@			| e->next = after->next
2013	movl	a0,a1@(4)		| e->prev = after
2014	movl	a1,a0@			| after->next = e
2015	movl	a1@,a0
2016	movl	a1,a0@(4)		| e->next->prev = e
2017	movw	d0,sr
2018	rts
2019
2020ENTRY(_remque)
2021	movw	sr,d0
2022	movw	#PSL_HIGHIPL,sr		| atomic
2023	movl	sp@(4),a0		| element to remove (e)
2024	movl	a0@,a1
2025	movl	a0@(4),a0
2026	movl	a0,a1@(4)		| e->next->prev = e->prev
2027	movl	a1,a0@			| e->prev->next = e->next
2028	movw	d0,sr
2029	rts
2030
2031/*
2032 * bzero(addr, count)
2033 */
2034ALTENTRY(blkclr, _bzero)
2035ENTRY(bzero)
2036	movl	sp@(4),a0	| address
2037	movl	sp@(8),d0	| count
2038	jeq	Lbzdone		| if zero, nothing to do
2039	movl	a0,d1
2040	btst	#0,d1		| address odd?
2041	jeq	Lbzeven		| no, can copy words
2042	clrb	a0@+		| yes, zero byte to get to even boundary
2043	subql	#1,d0		| decrement count
2044	jeq	Lbzdone		| none left, all done
2045Lbzeven:
2046	movl	d0,d1
2047	andl	#31,d0
2048	lsrl	#5,d1		| convert count to 8*longword count
2049	jeq	Lbzbyte		| no such blocks, zero byte at a time
2050Lbzloop:
2051	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
2052	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
2053	subql	#1,d1		| one more block zeroed
2054	jne	Lbzloop		| more to go, do it
2055	tstl	d0		| partial block left?
2056	jeq	Lbzdone		| no, all done
2057Lbzbyte:
2058	clrb	a0@+
2059	subql	#1,d0		| one more byte cleared
2060	jne	Lbzbyte		| more to go, do it
2061Lbzdone:
2062	rts
2063
2064/*
2065 * strlen(str)
2066 */
2067ENTRY(strlen)
2068	moveq	#-1,d0
2069	movl	sp@(4),a0	| string
2070Lslloop:
2071	addql	#1,d0		| increment count
2072	tstb	a0@+		| null?
2073	jne	Lslloop		| no, keep going
2074	rts
2075
2076/*
2077 * bcmp(s1, s2, len)
2078 *
2079 * WARNING!  This guy only works with counts up to 64K
2080 */
2081ENTRY(bcmp)
2082	movl	sp@(4),a0		| string 1
2083	movl	sp@(8),a1		| string 2
2084	moveq	#0,d0
2085	movw	sp@(14),d0		| length
2086	jeq	Lcmpdone		| if zero, nothing to do
2087	subqw	#1,d0			| set up for DBcc loop
2088Lcmploop:
2089	cmpmb	a0@+,a1@+		| equal?
2090	dbne	d0,Lcmploop		| yes, keep going
2091	addqw	#1,d0			| +1 gives zero on match
2092Lcmpdone:
2093	rts
2094
2095/*
2096 * {ov}bcopy(from, to, len)
2097 *
2098 * Works for counts up to 128K.
2099 */
2100ALTENTRY(ovbcopy, _bcopy)
2101ENTRY(bcopy)
2102	movl	sp@(12),d0		| get count
2103	jeq	Lcpyexit		| if zero, return
2104	movl	sp@(4),a0		| src address
2105	movl	sp@(8),a1		| dest address
2106	cmpl	a1,a0			| src before dest?
2107	jlt	Lcpyback		| yes, copy backwards (avoids overlap)
2108	movl	a0,d1
2109	btst	#0,d1			| src address odd?
2110	jeq	Lcfeven			| no, go check dest
2111	movb	a0@+,a1@+		| yes, copy a byte
2112	subql	#1,d0			| update count
2113	jeq	Lcpyexit		| exit if done
2114Lcfeven:
2115	movl	a1,d1
2116	btst	#0,d1			| dest address odd?
2117	jne	Lcfbyte			| yes, must copy by bytes
2118	movl	d0,d1			| no, get count
2119	lsrl	#2,d1			| convert to longwords
2120	jeq	Lcfbyte			| no longwords, copy bytes
2121	subql	#1,d1			| set up for dbf
2122Lcflloop:
2123	movl	a0@+,a1@+		| copy longwords
2124	dbf	d1,Lcflloop		| til done
2125	andl	#3,d0			| get remaining count
2126	jeq	Lcpyexit		| done if none
2127Lcfbyte:
2128	subql	#1,d0			| set up for dbf
2129Lcfbloop:
2130	movb	a0@+,a1@+		| copy bytes
2131	dbf	d0,Lcfbloop		| til done
2132Lcpyexit:
2133	rts
2134Lcpyback:
2135	addl	d0,a0			| add count to src
2136	addl	d0,a1			| add count to dest
2137	movl	a0,d1
2138	btst	#0,d1			| src address odd?
2139	jeq	Lcbeven			| no, go check dest
2140	movb	a0@-,a1@-		| yes, copy a byte
2141	subql	#1,d0			| update count
2142	jeq	Lcpyexit		| exit if done
2143Lcbeven:
2144	movl	a1,d1
2145	btst	#0,d1			| dest address odd?
2146	jne	Lcbbyte			| yes, must copy by bytes
2147	movl	d0,d1			| no, get count
2148	lsrl	#2,d1			| convert to longwords
2149	jeq	Lcbbyte			| no longwords, copy bytes
2150	subql	#1,d1			| set up for dbf
2151Lcblloop:
2152	movl	a0@-,a1@-		| copy longwords
2153	dbf	d1,Lcblloop		| til done
2154	andl	#3,d0			| get remaining count
2155	jeq	Lcpyexit		| done if none
2156Lcbbyte:
2157	subql	#1,d0			| set up for dbf
2158Lcbbloop:
2159	movb	a0@-,a1@-		| copy bytes
2160	dbf	d0,Lcbbloop		| til done
2161	rts
2162
2163/*
2164 * Emulate fancy VAX string operations:
2165 *	scanc(count, startc, table, mask)
2166 *	skpc(mask, count, startc)
2167 *	locc(mask, count, startc)
2168 */
2169ENTRY(scanc)
2170	movl	sp@(4),d0	| get length
2171	jeq	Lscdone		| nothing to do, return
2172	movl	sp@(8),a0	| start of scan
2173	movl	sp@(12),a1	| table to compare with
2174	movb	sp@(19),d1	| and mask to use
2175	movw	d2,sp@-		| need a scratch register
2176	clrw	d2		| clear it out
2177	subqw	#1,d0		| adjust for dbra
2178Lscloop:
2179	movb	a0@+,d2		| get character
2180	movb	a1@(0,d2:w),d2	| get table entry
2181	andb	d1,d2		| mask it
2182	dbne	d0,Lscloop	| keep going til no more or non-zero
2183	addqw	#1,d0		| overshot by one
2184	movw	sp@+,d2		| restore scratch
2185Lscdone:
2186	rts
2187
2188ENTRY(skpc)
2189	movl	sp@(8),d0	| get length
2190	jeq	Lskdone		| nothing to do, return
2191	movb	sp@(7),d1	| mask to use
2192	movl	sp@(12),a0	| where to start
2193	subqw	#1,d0		| adjust for dbcc
2194Lskloop:
2195	cmpb	a0@+,d1		| compate with mask
2196	dbne	d0,Lskloop	| keep going til no more or zero
2197	addqw	#1,d0		| overshot by one
2198Lskdone:
2199	rts
2200
2201ENTRY(locc)
2202	movl	sp@(8),d0	| get length
2203	jeq	Llcdone		| nothing to do, return
2204	movb	sp@(7),d1	| mask to use
2205	movl	sp@(12),a0	| where to start
2206	subqw	#1,d0		| adjust for dbcc
2207Llcloop:
2208	cmpb	a0@+,d1		| compate with mask
2209	dbeq	d0,Llcloop	| keep going til no more or non-zero
2210	addqw	#1,d0		| overshot by one
2211Llcdone:
2212	rts
2213
2214/*
2215 * Emulate VAX FFS (find first set) instruction.
2216 */
2217ENTRY(ffs)
2218	moveq	#-1,d0
2219	movl	sp@(4),d1
2220	jeq	Lffsdone
2221Lffsloop:
2222	addql	#1,d0
2223	btst	d0,d1
2224	jeq	Lffsloop
2225Lffsdone:
2226	addql	#1,d0
2227	rts
2228
2229#ifdef FPCOPROC
2230/*
2231 * Save and restore 68881 state.
2232 * Pretty awful looking since our assembler does not
2233 * recognize FP mnemonics.
2234 */
2235ENTRY(m68881_save)
2236	movl	sp@(4),a0		| save area pointer
2237	fsave	a0@			| save state
2238	tstb	a0@			| null state frame?
2239	jeq	Lm68881sdone		| yes, all done
2240	fmovem fp0-fp7,a0@(216)		| save FP general registers
2241	fmovem fpcr/fpsr/fpi,a0@(312)	| save FP control registers
2242Lm68881sdone:
2243	rts
2244
2245ENTRY(m68881_restore)
2246	movl	sp@(4),a0		| save area pointer
2247	tstb	a0@			| null state frame?
2248	jeq	Lm68881rdone		| yes, easy
2249	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
2250	fmovem	a0@(216),fp0-fp7	| restore FP general registers
2251Lm68881rdone:
2252	frestore a0@			| restore state
2253	rts
2254
2255/* LUNA */
2256
2257	.globl	_fpp_svarea
2258
2259/* Fpp is MC68882 ? */
2260ENTRY(is_68882)
2261	frestore _fppnull	| initialize fpp
2262	movl	#2,d0
2263	fmovecr	#0,fp1
2264	fsinx	fp1,fp2
2265	lea	_fpp_svarea,a0	| save area
2266	movw	sr,d1		| save status reg.
2267	movw	#0x2700,sr	| mask intrrupt
2268	fsave	a0@		| save fpp context
2269	movw	d1,sr		| restore status reg.
2270	movl	a0@,d1
2271	andl	#0x00ff0000,d1  | check status field
2272	cmpl	#0x00180000,d1  | 68881(idle)?
2273	beq	_is81
2274	cmpl	#0x00b40000,d1	| 68881(busy)?
2275	beq	_is81
2276	cmpl	#0x00380000,d1	| 68882(idle)?
2277	beq	_is82
2278	cmpl	#0x00d40000,d1	| 68882(busy)?
2279	beq	_is82
2280	bra	_is82out	| default 68881
2281_is81:
2282	clrl	d0
2283	bra	_is82out
2284_is82:
2285	movl	#1,d0
2286_is82out:
2287	frestore a0@
2288	rts
2289
2290#ifdef	OLD_LUNA
2291/* We have fpp ? */
2292ENTRY(havefpp)
2293	movl	a2,sp@-
2294	clrl	d0
2295	movl	vb,a2
2296	movl	a2@(FLINE_VEC),a0	| save vectors
2297	movl	a2@(COPRO_VEC),a1
2298	movl	sp,d1
2299	movl	#_fpvec,a2@(FLINE_VEC)	| change vectors
2300	movl	#_fpvec,a2@(COPRO_VEC)
2301	fnop				| cause exception ?
2302	movl	#1,d0
2303_fpvec:	movl	a0,a2@(FLINE_VEC)	| restore vectors
2304	movl	a1,a2@(COPRO_VEC)
2305	movl	d1,sp
2306	movl	sp@+,a2
2307	rts
2308#endif
2309#endif
2310
2311/*
2312 * Handle the nitty-gritty of rebooting the machine.
2313 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
2314 * Note that we must be running in an address range that is mapped one-to-one
2315 * logical to physical so that the PC is still valid immediately after the MMU
2316 * is turned off.  We have conveniently mapped the last page of physical
2317 * memory this way.
2318 */
2319	.globl	_doboot
2320_doboot:
2321	movl	#0x41000004,a0
2322	movl	a0@,a1			| get PROM restart entry address
2323#if defined(LUNA2)
2324	cmpl	#-2,_mmutype		| 68040?
2325	jne	LmotommuF		| no, skip
2326
2327	movw	#PSL_HIGHIPL,sr		| no interrupts
2328
2329	movl	#0x41000000,a0
2330	movl	a0@,d0
2331	movc	d0,isp			| set ISP
2332
2333	.word	0xf4f8			| cpusha bc
2334	movl	#0,d0
2335	movc	d0,cacr			| caches off
2336	movql	#0,d0
2337	.long	0x4e7b0004		| movc d0,itt0
2338	.long	0x4e7b0005		| movc d0,itt1
2339	.long	0x4e7b0006		| movc d0,dtt0
2340	.long	0x4e7b0007		| movc d0,dtt1
2341
2342	.long	0x4e7b0003		| movc d0,tc
2343
2344	jmp	a1@			| goto REBOOT
2345LmotommuF:
2346#endif
2347	movl	#CACHE_OFF,d0
2348	movc	d0,cacr			| disable on-chip cache(s)
2349	movl	#_tcroff,a0		| value for pmove to TC (turn off MMU)
2350	pmove	a0@,tc			| disable MMU
2351	jmp	a1@			| goto REBOOT
2352
2353	.data
2354	.globl	_machineid,_mmutype
2355_machineid:
2356	.long	1		| default to LUNA-I
2357_mmutype:
2358	.long	-1		| default to 68030 PMMU
2359	.globl	_protorp,_protott0,_protott1
2360_protorp:
2361	.long	0,0		| prototype root pointer
2362_protott0:
2363	.long	0x403f8543	| tt0 (for LUNA1 kernel 0x40000000-0x7fffffff)
2364_protott1:
2365	.long	0x807F8543	| tt1 (for LUNA1 kernel 0x80000000-0xffffffff)
2366_mapping_tc:
2367	.long	0
2368	.globl	_cold
2369_cold:
2370	.long	1		| cold start flag
2371	.globl	_want_resched
2372_want_resched:
2373	.long	0
2374	.globl	_proc0paddr
2375_proc0paddr:
2376	.long	0		| KVA of proc0 u-area
2377
2378	.globl	_tcroff
2379_tcroff:
2380	.long	0		| TC reg. reset flag
2381
2382#ifdef FPCOPROC
2383	.globl	_fppnull
2384_fppnull:
2385	.long	0
2386#endif
2387	.globl	_clock_on
2388_clock_on:
2389	.long	0		| clock is enable ?
2390	.globl	_dipswitch
2391_dipswitch:
2392	.word	0		| dipsw(front panel) value
2393	.globl	_KernInter
2394_KernInter:			| Kernel InterFace Field
2395	.space	KIFF_SIZE
2396#ifdef DEBUG
2397	.globl	fulltflush, fullcflush
2398fulltflush:
2399	.long	0
2400fullcflush:
2401	.long	0
2402#endif
2403#ifdef HPFPLIB
2404/*
2405 * Undefined symbols from hpux_float.o:
2406 *
2407 * kdb_printf:	A kernel debugger print routine, we just use printf instead.
2408 * processor:	HP-UX equiv. of machineid, set to 3 if it is a 68040.
2409 * u:		Ye ole u-area.  The code wants to grab the first longword
2410 *		indirect off of that and clear the 0x40000 bit there.
2411 *		Oddly enough this was incorrect even in HP-UX!
2412 * runrun:	Old name for want_resched.
2413 */
2414	.globl	_kdb_printf,_processor,_u,_runrun
2415_kdb_printf:
2416	.long	_printf
2417_processor:
2418	.long	0
2419_u:
2420	.long	.+4
2421	.long	0
2422	.set	_runrun,_want_resched
2423#endif
2424/* interrupt counters */
2425	.globl	_intrcnt,_eintrcnt,_intrnames,_eintrnames
2426_intrnames:
2427	.asciz	"spur"
2428	.asciz	"lev1"
2429	.asciz	"lev2"
2430	.asciz	"lev3"
2431	.asciz	"lev4"
2432	.asciz	"clock"
2433	.asciz	"lev7"
2434	.asciz	"nmi"
2435_eintrnames:
2436	.even
2437_intrcnt:
2438	.long	0,0,0,0,0,0,0,0,0
2439_eintrcnt:
2440