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