xref: /original-bsd/sys/hp300/hp300/locore.s (revision 68549010)
1/*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1980, 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department.
9 *
10 * %sccs.include.redist.c%
11 *
12 * from: Utah $Hdr: locore.s 1.58 91/04/22$
13 *
14 *	@(#)locore.s	7.12 (Berkeley) 07/25/91
15 */
16
17#include "assym.s"
18#include "vectors.s"
19
20#define MMUADDR(ar)	movl	_MMUbase,ar
21#define CLKADDR(ar)	movl	_CLKbase,ar
22
23	.text
24/*
25 * This is where we wind up if the kernel jumps to location 0.
26 * (i.e. a bogus PC)  This is known to immediately follow the vector
27 * table and is hence at 0x400 (see reset vector in vectors.s).
28 */
29	.globl	_panic
30	pea	Ljmp0panic
31	jbsr	_panic
32	/* NOTREACHED */
33Ljmp0panic:
34	.asciz	"kernel jump to zero"
35	.even
36
37/*
38 * Do a dump.
39 * Called by auto-restart.
40 */
41	.globl	_dumpsys
42	.globl	_doadump
43_doadump:
44	jbsr	_dumpsys
45	jbsr	_doboot
46	/*NOTREACHED*/
47
48/*
49 * Trap/interrupt vector routines
50 */
51
52	.globl	_trap, _nofault, _longjmp
53_buserr:
54	tstl	_nofault		| device probe?
55	jeq	_addrerr		| no, handle as usual
56	movl	_nofault,sp@-		| yes,
57	jbsr	_longjmp		|  longjmp(nofault)
58_addrerr:
59	clrw	sp@-			| pad SR to longword
60	moveml	#0xFFFF,sp@-		| save user registers
61	movl	usp,a0			| save the user SP
62	movl	a0,sp@(60)		|   in the savearea
63	lea	sp@(64),a1		| grab base of HW berr frame
64	moveq	#0,d0
65	movw	a1@(12),d0		| grab SSW for fault processing
66	btst	#12,d0			| RB set?
67	jeq	LbeX0			| no, test RC
68	bset	#14,d0			| yes, must set FB
69	movw	d0,a1@(12)		| for hardware too
70LbeX0:
71	btst	#13,d0			| RC set?
72	jeq	LbeX1			| no, skip
73	bset	#15,d0			| yes, must set FC
74	movw	d0,a1@(12)		| for hardware too
75LbeX1:
76	btst	#8,d0			| data fault?
77	jeq	Lbe0			| no, check for hard cases
78	movl	a1@(18),d1		| fault address is as given in frame
79	jra	Lbe10			| thats it
80Lbe0:
81	btst	#4,a1@(8)		| long (type B) stack frame?
82	jne	Lbe4			| yes, go handle
83	movl	a1@(4),d1		| no, can use save PC
84	btst	#14,d0			| FB set?
85	jeq	Lbe3			| no, try FC
86	addql	#4,d1			| yes, adjust address
87	jra	Lbe10			| done
88Lbe3:
89	btst	#15,d0			| FC set?
90	jeq	Lbe10			| no, done
91	addql	#2,d1			| yes, adjust address
92	jra	Lbe10			| done
93Lbe4:
94	movl	a1@(38),d1		| long format, use stage B address
95	btst	#15,d0			| FC set?
96	jeq	Lbe10			| no, all done
97	subql	#2,d1			| yes, adjust address
98Lbe10:
99	movl	d1,sp@-			| push fault VA
100	movl	d0,sp@-			| and padded SSW
101	movw	a1@(8),d0		| get frame format/vector offset
102	andw	#0x0FFF,d0		| clear out frame format
103	cmpw	#12,d0			| address error vector?
104	jeq	Lisaerr			| yes, go to it
105#if defined(HP330) || defined(HP360) || defined(HP370)
106	tstl	_mmutype		| HP MMU?
107	jeq	Lbehpmmu		| yes, skip
108	movl	d1,a0			| fault address
109	ptestr	#1,a0@,#7		| do a table search
110	pmove	psr,sp@			| save result
111	btst	#7,sp@			| bus error bit set?
112	jeq	Lismerr			| no, must be MMU fault
113	clrw	sp@			| yes, re-clear pad word
114	jra	Lisberr			| and process as normal bus error
115Lbehpmmu:
116#endif
117#if defined(HP320) || defined(HP350)
118	MMUADDR(a0)
119	movl	a0@(MMUSTAT),d0		| read status
120	btst	#3,d0			| MMU fault?
121	jeq	Lisberr			| no, just a non-MMU bus error so skip
122	andl	#~MMU_FAULT,a0@(MMUSTAT)| yes, clear fault bits
123	movw	d0,sp@			| pass MMU stat in upper half of code
124#endif
125Lismerr:
126	movl	#T_MMUFLT,sp@-		| show that we are an MMU fault
127	jra	Ltrapnstkadj		| and deal with it
128Lisaerr:
129	movl	#T_ADDRERR,sp@-		| mark address error
130	jra	Ltrapnstkadj		| and deal with it
131Lisberr:
132	movl	#T_BUSERR,sp@-		| mark bus error
133Ltrapnstkadj:
134	jbsr	_trap			| handle the error
135	lea	sp@(12),sp		| pop value args
136	movl	sp@(60),a0		| restore user SP
137	movl	a0,usp			|   from save area
138	movw	sp@(64),d0		| need to adjust stack?
139	jne	Lstkadj			| yes, go to it
140	moveml	sp@+,#0x7FFF		| no, restore most user regs
141	addql	#6,sp			| toss SSP and pad
142	jra	rei			| all done
143Lstkadj:
144	lea	sp@(66),a1		| pointer to HW frame
145	addql	#8,a1			| source pointer
146	movl	a1,a0			| source
147	addw	d0,a0			|  + hole size = dest pointer
148	movl	a1@-,a0@-		| copy
149	movl	a1@-,a0@-		|  8 bytes
150	movl	a0,sp@(60)		| new SSP
151	moveml	sp@+,#0x7FFF		| restore user registers
152	movl	sp@,sp			| and our SP
153	jra	rei			| all done
154
155/*
156 * FP exceptions.
157 */
158_fpfline:
159	jra	_illinst
160
161_fpunsupp:
162	jra	_illinst
163
164/*
165 * Handles all other FP coprocessor exceptions.
166 * Note that since some FP exceptions generate mid-instruction frames
167 * and may cause signal delivery, we need to test for stack adjustment
168 * after the trap call.
169 */
170_fpfault:
171#ifdef FPCOPROC
172	clrw	sp@-		| pad SR to longword
173	moveml	#0xFFFF,sp@-	| save user registers
174	movl	usp,a0		| and save
175	movl	a0,sp@(60)	|   the user stack pointer
176	clrl	sp@-		| no VA arg
177	movl	_curpcb,a0	| current pcb
178	lea	a0@(PCB_FPCTX),a0 | address of FP savearea
179	fsave	a0@		| save state
180	tstb	a0@		| null state frame?
181	jeq	Lfptnull	| yes, safe
182	clrw	d0		| no, need to tweak BIU
183	movb	a0@(1),d0	| get frame size
184	bset	#3,a0@(0,d0:w)	| set exc_pend bit of BIU
185Lfptnull:
186	fmovem	fpsr,sp@-	| push fpsr as code argument
187	frestore a0@		| restore state
188	movl	#T_FPERR,sp@-	| push type arg
189	jra	Ltrapnstkadj	| call trap and deal with stack cleanup
190#else
191	jra	_badtrap	| treat as an unexpected trap
192#endif
193
194/*
195 * Coprocessor and format errors can generate mid-instruction stack
196 * frames and cause signal delivery hence we need to check for potential
197 * stack adjustment.
198 */
199_coperr:
200	clrw	sp@-
201	moveml	#0xFFFF,sp@-
202	movl	usp,a0		| get and save
203	movl	a0,sp@(60)	|   the user stack pointer
204	clrl	sp@-		| no VA arg
205	clrl	sp@-		| or code arg
206	movl	#T_COPERR,sp@-	| push trap type
207	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
208
209_fmterr:
210	clrw	sp@-
211	moveml	#0xFFFF,sp@-
212	movl	usp,a0		| get and save
213	movl	a0,sp@(60)	|   the user stack pointer
214	clrl	sp@-		| no VA arg
215	clrl	sp@-		| or code arg
216	movl	#T_FMTERR,sp@-	| push trap type
217	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
218
219/*
220 * Other exceptions only cause four and six word stack frame and require
221 * no post-trap stack adjustment.
222 */
223_illinst:
224	clrw	sp@-
225	moveml	#0xFFFF,sp@-
226	moveq	#T_ILLINST,d0
227	jra	fault
228
229_zerodiv:
230	clrw	sp@-
231	moveml	#0xFFFF,sp@-
232	moveq	#T_ZERODIV,d0
233	jra	fault
234
235_chkinst:
236	clrw	sp@-
237	moveml	#0xFFFF,sp@-
238	moveq	#T_CHKINST,d0
239	jra	fault
240
241_trapvinst:
242	clrw	sp@-
243	moveml	#0xFFFF,sp@-
244	moveq	#T_TRAPVINST,d0
245	jra	fault
246
247_privinst:
248	clrw	sp@-
249	moveml	#0xFFFF,sp@-
250	moveq	#T_PRIVINST,d0
251	jra	fault
252
253	.globl	fault
254fault:
255	movl	usp,a0			| get and save
256	movl	a0,sp@(60)		|   the user stack pointer
257	clrl	sp@-			| no VA arg
258	clrl	sp@-			| or code arg
259	movl	d0,sp@-			| push trap type
260	jbsr	_trap			| handle trap
261	lea	sp@(12),sp		| pop value args
262	movl	sp@(60),a0		| restore
263	movl	a0,usp			|   user SP
264	moveml	sp@+,#0x7FFF		| restore most user regs
265	addql	#6,sp			| pop SP and pad word
266	jra	rei			| all done
267
268	.globl	_straytrap
269_badtrap:
270	clrw	sp@-			| pad SR
271	moveml	#0xC0C0,sp@-		| save scratch regs
272	movw	sp@(24),sp@-		| push exception vector info
273	clrw	sp@-
274	movl	sp@(24),sp@-		| and PC
275	jbsr	_straytrap		| report
276	addql	#8,sp			| pop args
277	moveml	sp@+,#0x0303		| restore regs
278	addql	#2,sp			| pop padding
279	jra	rei			| all done
280
281	.globl	_syscall
282_trap0:
283	clrw	sp@-			| pad SR to longword
284	moveml	#0xFFFF,sp@-		| save user registers
285	movl	usp,a0			| save the user SP
286	movl	a0,sp@(60)		|   in the savearea
287	movl	d0,sp@-			| push syscall number
288	jbsr	_syscall		| handle it
289	addql	#4,sp			| pop syscall arg
290	movl	sp@(60),a0		| grab and restore
291	movl	a0,usp			|   user SP
292	moveml	sp@+,#0x7FFF		| restore most registers
293	addql	#6,sp			| pop SSP and align word
294	jra	rei			| all done
295
296/*
297 * Routines for traps 1 and 2.  The meaning of the two traps depends
298 * on whether we are an HPUX compatible process or a native 4.3 process.
299 * Our native 4.3 implementation uses trap 1 as sigreturn() and trap 2
300 * as a breakpoint trap.  HPUX uses trap 1 for a breakpoint, so we have
301 * to make adjustments so that trap 2 is used for sigreturn.
302 */
303_trap1:
304	btst	#PCB_TRCB,pcbflag	| being traced by an HPUX process?
305	jeq	sigreturn		| no, trap1 is sigreturn
306	jra	_trace			| yes, trap1 is breakpoint
307
308_trap2:
309	btst	#PCB_TRCB,pcbflag	| being traced by an HPUX process?
310	jeq	_trace			| no, trap2 is breakpoint
311	jra	sigreturn		| yes, trap2 is sigreturn
312
313/*
314 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
315 *	cachectl(command, addr, length)
316 * command in d0, addr in a1, length in d1
317 */
318	.globl	_cachectl
319_trap12:
320	movl	d1,sp@-			| push length
321	movl	a1,sp@-			| push addr
322	movl	d0,sp@-			| push command
323	jbsr	_cachectl		| do it
324	lea	sp@(12),sp		| pop args
325	jra	rei			| all done
326
327/*
328 * Trap 15 is used for:
329 *	- KGDB traps
330 *	- trace traps for SUN binaries (not fully supported yet)
331 * We just pass it on and let trap() sort it all out
332 */
333_trap15:
334	clrw	sp@-
335	moveml	#0xFFFF,sp@-
336#ifdef KGDB
337	moveq	#T_TRAP15,d0
338	movl	sp@(64),d1		| from user mode?
339	andl	#PSL_S,d1
340	jeq	fault
341	movl	d0,sp@-
342	.globl	_kgdb_trap_glue
343	jbsr	_kgdb_trap_glue		| returns if no debugger
344	addl	#4,sp
345#endif
346	moveq	#T_TRAP15,d0
347	jra	fault
348
349/*
350 * Hit a breakpoint (trap 1 or 2) instruction.
351 * Push the code and treat as a normal fault.
352 */
353_trace:
354	clrw	sp@-
355	moveml	#0xFFFF,sp@-
356#ifdef KGDB
357	moveq	#T_TRACE,d0
358	movl	sp@(64),d1		| from user mode?
359	andl	#PSL_S,d1
360	jeq	fault
361	movl	d0,sp@-
362	jbsr	_kgdb_trap_glue		| returns if no debugger
363	addl	#4,sp
364#endif
365	moveq	#T_TRACE,d0
366	jra	fault
367
368/*
369 * The sigreturn() syscall comes here.  It requires special handling
370 * because we must open a hole in the stack to fill in the (possibly much
371 * larger) original stack frame.
372 */
373sigreturn:
374	lea	sp@(-84),sp		| leave enough space for largest frame
375	movl	sp@(84),sp@		| move up current 8 byte frame
376	movl	sp@(88),sp@(4)
377	movw	#84,sp@-		| default: adjust by 84 bytes
378	moveml	#0xFFFF,sp@-		| save user registers
379	movl	usp,a0			| save the user SP
380	movl	a0,sp@(60)		|   in the savearea
381	movl	#SYS_sigreturn,sp@-	| push syscall number
382	jbsr	_syscall		| handle it
383	addql	#4,sp			| pop syscall#
384	movl	sp@(60),a0		| grab and restore
385	movl	a0,usp			|   user SP
386	lea	sp@(64),a1		| pointer to HW frame
387	movw	a1@+,d0			| do we need to adjust the stack?
388	jeq	Lsigr1			| no, just continue
389	moveq	#92,d1			| total size
390	subw	d0,d1			|  - hole size = frame size
391	lea	a1@(92),a0		| destination
392	addw	d1,a1			| source
393	lsrw	#1,d1			| convert to word count
394	subqw	#1,d1			| minus 1 for dbf
395Lsigrlp:
396	movw	a1@-,a0@-		| copy a word
397	dbf	d1,Lsigrlp		| continue
398	movl	a0,a1			| new HW frame base
399Lsigr1:
400	movl	a1,sp@(60)		| new SP value
401	moveml	sp@+,#0x7FFF		| restore user registers
402	movl	sp@,sp			| and our SP
403	jra	rei			| all done
404
405/*
406 * Interrupt handlers.
407 * All DIO device interrupts are auto-vectored.  Most can be configured
408 * to interrupt in the range IPL3 to IPL5.  Here are our assignments:
409 *
410 *	Level 0:	Spurious: ignored.
411 *	Level 1:	HIL
412 *	Level 2:
413 *	Level 3:	Internal HP-IB
414 *	Level 4:	"Fast" HP-IBs, SCSI
415 *	Level 5:	DMA, Ethernet, Built-in RS232
416 *	Level 6:	Clock
417 *	Level 7:	Non-maskable: parity errors, RESET key
418 */
419	.globl	_hilint, _intrhand, _hardclock, _nmihand
420
421_spurintr:
422	addql	#1,_intrcnt+0
423	addql	#1,_cnt+V_INTR
424	jra	rei
425
426_lev1intr:
427	addql	#1,_intrcnt+4
428	clrw	sp@-
429	moveml	#0xC0C0,sp@-
430	jbsr	_hilint
431	moveml	sp@+,#0x0303
432	addql	#2,sp
433	addql	#1,_cnt+V_INTR
434	jra	rei
435
436/* check for DMA first to reduce overhead */
437_lev5intr:
438	clrw	sp@-
439	moveml	#0xC0C0,sp@-
440	jbsr	_dmaintr
441	tstl	d0
442	jeq	Lnotdma
443	addql	#1,_intrcnt+24
444	moveml	sp@+,#0x0303
445	addql	#2,sp
446	addql	#1,_cnt+V_INTR
447	jra	rei
448
449_lev2intr:
450_lev3intr:
451_lev4intr:
452	clrw	sp@-
453	moveml	#0xC0C0,sp@-
454Lnotdma:
455	lea	_intrcnt,a0
456	movw	sp@(24),d0		| use vector offset
457	andw	#0xfff,d0		|   sans frame type
458	addql	#1,a0@(-0x60,d0:w)	|     to increment apropos counter
459	movw	sr,sp@-			| push current SR value
460	clrw	sp@-			|    padded to longword
461	jbsr	_intrhand		| handle interrupt
462	addql	#4,sp			| pop SR
463	moveml	sp@+,#0x0303
464	addql	#2,sp
465	addql	#1,_cnt+V_INTR
466	jra	rei
467
468_lev6intr:
469	clrw	sp@-
470	moveml	#0xC0C0,sp@-
471#ifdef DEBUG
472	.globl	_panicstr, _regdump, _panic
473	tstl	timebomb		| set to go off?
474	jeq	Lnobomb			| no, skip it
475	subql	#1,timebomb		| decrement
476	jne	Lnobomb			| not ready to go off
477	moveml	sp@+,#0x0303		| temporarily restore regs
478	jra	Lbomb			| go die
479Lnobomb:
480	cmpl	#_kstack+NBPG,sp	| are we still in stack pages?
481	jcc	Lstackok		| yes, continue normally
482	tstl	_curproc		| if !curproc could have swtch_exit'ed,
483	jeq	Lstackok		|     might be on tmpstk
484	tstl	_panicstr		| have we paniced?
485	jne	Lstackok		| yes, do not re-panic
486	lea	tmpstk,sp		| no, switch to tmpstk
487	moveml	#0xFFFF,sp@-		| push all registers
488	movl	#Lstkrip,sp@-		| push panic message
489	jbsr	_printf			| preview
490	addql	#4,sp
491	movl	sp,a0			| remember this spot
492	movl	#256,sp@-		| longword count
493	movl	a0,sp@-			| and reg pointer
494	jbsr	_regdump		| dump core
495	addql	#8,sp			| pop params
496	movl	#Lstkrip,sp@-		| push panic message
497	jbsr	_panic			| ES and D
498Lbomb:
499	moveml	#0xFFFF,sp@-		| push all registers
500	movl	sp,a0			| remember this spot
501	movl	#256,sp@-		| longword count
502	movl	a0,sp@-			| and reg pointer
503	jbsr	_regdump		| dump core
504	addql	#8,sp			| pop params
505	movl	#Lbomrip,sp@-		| push panic message
506	jbsr	_panic			| ES and D
507Lstkrip:
508	.asciz	"k-stack overflow"
509Lbomrip:
510	.asciz	"timebomb"
511	.even
512Lstackok:
513#endif
514	CLKADDR(a0)
515	movb	a0@(CLKSR),d0		| read clock status
516#ifdef PROFTIMER
517	.globl  _profon
518	tstb	_profon			| profile clock on?
519	jeq     Ltimer1			| no, then must be timer1 interrupt
520	btst	#2,d0			| timer3 interrupt?
521	jeq     Ltimer1			| no, must be timer1
522	movb	a0@(CLKMSB3),d1		| clear timer3 interrupt
523	lea	sp@(16),a1		| get pointer to PS
524#ifdef GPROF
525	.globl	_profclock
526	movl	d0,sp@-			| save status so jsr will not clobber
527	movl	a1@,sp@-		| push padded PS
528	movl	a1@(4),sp@-		| push PC
529	jbsr	_profclock		| profclock(pc, ps)
530	addql	#8,sp			| pop params
531#else
532	btst	#5,a1@(2)		| saved PS in user mode?
533	jne	Lttimer1		| no, go check timer1
534	movl	_curpcb,a0		| current pcb
535	tstl	a0@(U_PROFSCALE)	| process being profiled?
536	jeq	Lttimer1		| no, go check timer1
537	movl	d0,sp@-			| save status so jsr will not clobber
538	movl	#1,sp@-
539	pea	a0@(U_PROF)
540	movl	a1@(4),sp@-
541	jbsr    _addupc			| addupc(pc, &u.u_prof, 1)
542	lea	sp@(12),sp		| pop params
543#endif
544	addql	#1,_intrcnt+32		| add another profile clock interrupt
545	movl	sp@+,d0			| get saved clock status
546	CLKADDR(a0)
547Lttimer1:
548	btst	#0,d0			| timer1 interrupt?
549	jeq     Ltimend		        | no, check state of kernel profiling
550Ltimer1:
551#endif
552	movb	a0@(CLKMSB1),d1		| clear timer1 interrupt
553	lea	sp@(16),a1		| get pointer to PS
554	movl	a1@,sp@-		| push padded PS
555	movl	a1@(4),sp@-		| push PC
556	jbsr	_hardclock		| call generic clock int routine
557	addql	#8,sp			| pop params
558	addql	#1,_intrcnt+28		| add another system clock interrupt
559#ifdef PROFTIMER
560Ltimend:
561#ifdef GPROF
562	.globl	_profiling, _startprofclock
563	tstl	_profiling		| kernel profiling desired?
564	jne	Ltimdone		| no, all done
565	bset	#7,_profon		| mark continuous timing
566	jne	Ltimdone		| was already enabled, all done
567	jbsr	_startprofclock		| else turn it on
568Ltimdone:
569#endif
570#endif
571	moveml	sp@+,#0x0303		| restore scratch regs
572	addql	#2,sp			| pop pad word
573	addql	#1,_cnt+V_INTR		| chalk up another interrupt
574	jra	rei			| all done
575
576_lev7intr:
577#ifdef PROFTIMER
578	addql	#1,_intrcnt+36
579#else
580	addql	#1,_intrcnt+32
581#endif
582	clrw	sp@-			| pad SR to longword
583	moveml	#0xFFFF,sp@-		| save registers
584	movl	usp,a0			| and save
585	movl	a0,sp@(60)		|   the user stack pointer
586	jbsr	_nmihand		| call handler
587	movl	sp@(60),a0		| restore
588	movl	a0,usp			|   user SP
589	moveml	sp@+,#0x7FFF		| and remaining registers
590	addql	#6,sp			| pop SSP and align word
591	jra	rei			| all done
592
593/*
594 * Emulation of VAX REI instruction.
595 *
596 * This code deals with checking for and servicing ASTs
597 * (profiling, scheduling) and software interrupts (network, softclock).
598 * We check for ASTs first, just like the VAX.  To avoid excess overhead
599 * the T_ASTFLT handling code will also check for software interrupts so we
600 * do not have to do it here.
601 *
602 * This code is complicated by the fact that sendsig may have been called
603 * necessitating a stack cleanup.  A cleanup should only be needed at this
604 * point for coprocessor mid-instruction frames (type 9), but we also test
605 * for bus error frames (type 10 and 11).
606 */
607	.comm	_ssir,1
608	.globl	_astpending
609rei:
610#ifdef DEBUG
611	tstl	_panicstr		| have we paniced?
612	jne	Ldorte			| yes, do not make matters worse
613#endif
614	tstl	_astpending		| AST pending?
615	jeq	Lchksir			| no, go check for SIR
616	btst	#5,sp@			| yes, are we returning to user mode?
617	jne	Lchksir			| no, go check for SIR
618	clrw	sp@-			| pad SR to longword
619	moveml	#0xFFFF,sp@-		| save all registers
620	movl	usp,a1			| including
621	movl	a1,sp@(60)		|    the users SP
622	clrl	sp@-			| VA == none
623	clrl	sp@-			| code == none
624	movl	#T_ASTFLT,sp@-		| type == async system trap
625	jbsr	_trap			| go handle it
626	lea	sp@(12),sp		| pop value args
627	movl	sp@(60),a0		| restore
628	movl	a0,usp			|   user SP
629	moveml	sp@+,#0x7FFF		| and all remaining registers
630	addql	#4,sp			| toss SSP
631	tstw	sp@+			| do we need to clean up stack?
632	jeq	Ldorte			| no, just continue
633	btst	#7,sp@(6)		| type 9/10/11 frame?
634	jeq	Ldorte			| no, nothing to do
635	btst	#5,sp@(6)		| type 9?
636	jne	Last1			| no, skip
637	movw	sp@,sp@(12)		| yes, push down SR
638	movl	sp@(2),sp@(14)		| and PC
639	clrw	sp@(18)			| and mark as type 0 frame
640	lea	sp@(12),sp		| clean the excess
641	jra	Ldorte			| all done
642Last1:
643	btst	#4,sp@(6)		| type 10?
644	jne	Last2			| no, skip
645	movw	sp@,sp@(24)		| yes, push down SR
646	movl	sp@(2),sp@(26)		| and PC
647	clrw	sp@(30)			| and mark as type 0 frame
648	lea	sp@(24),sp		| clean the excess
649	jra	Ldorte			| all done
650Last2:
651	movw	sp@,sp@(84)		| type 11, push down SR
652	movl	sp@(2),sp@(86)		| and PC
653	clrw	sp@(90)			| and mark as type 0 frame
654	lea	sp@(84),sp		| clean the excess
655	jra	Ldorte			| all done
656Lchksir:
657	tstb	_ssir			| SIR pending?
658	jeq	Ldorte			| no, all done
659	movl	d0,sp@-			| need a scratch register
660	movw	sp@(4),d0		| get SR
661	andw	#PSL_IPL7,d0		| mask all but IPL
662	jne	Lnosir			| came from interrupt, no can do
663	movl	sp@+,d0			| restore scratch register
664Lgotsir:
665	movw	#SPL1,sr		| prevent others from servicing int
666	tstb	_ssir			| too late?
667	jeq	Ldorte			| yes, oh well...
668	clrw	sp@-			| pad SR to longword
669	moveml	#0xFFFF,sp@-		| save all registers
670	movl	usp,a1			| including
671	movl	a1,sp@(60)		|    the users SP
672	clrl	sp@-			| VA == none
673	clrl	sp@-			| code == none
674	movl	#T_SSIR,sp@-		| type == software interrupt
675	jbsr	_trap			| go handle it
676	lea	sp@(12),sp		| pop value args
677	movl	sp@(60),a0		| restore
678	movl	a0,usp			|   user SP
679	moveml	sp@+,#0x7FFF		| and all remaining registers
680	addql	#6,sp			| pop SSP and align word
681	rte
682Lnosir:
683	movl	sp@+,d0			| restore scratch register
684Ldorte:
685	rte				| real return
686
687/*
688 * Kernel access to the current processes kernel stack is via a fixed
689 * virtual address.  It is at the same address as in the users VA space.
690 * Umap contains the KVA of the first of UPAGES PTEs mapping VA _kstack.
691 */
692	.data
693	.set	_kstack,USRSTACK
694_Umap:	.long	0
695	.globl	_kstack, _Umap
696
697#define	RELOC(var, ar)	\
698	lea	var,ar;	\
699	addl	a5,ar
700
701/*
702 * Initialization
703 *
704 * A5 contains physical load point from boot
705 * VBR contains zero from ROM.  Exceptions will continue to vector
706 * through ROM until MMU is turned on at which time they will vector
707 * through our table (vectors.s).
708 */
709	.comm	_lowram,4
710
711	.text
712	.globl	_edata
713	.globl	_etext,_end
714	.globl	start
715start:
716	movw	#PSL_HIGHIPL,sr		| no interrupts
717	RELOC(tmpstk, a0)
718	movl	a0,sp			| give ourselves a temporary stack
719	RELOC(_lowram, a0)
720	movl	a5,a0@			| store start of physical memory
721	movl	#CACHE_OFF,d0
722	movc	d0,cacr			| clear and disable on-chip cache(s)
723
724/* determine our CPU/MMU combo - check for all regardless of kernel config */
725	movl	#INTIOBASE+MMUBASE,a1
726	movl	#0x200,d0		| data freeze bit
727	movc	d0,cacr			|   only exists on 68030
728	movc	cacr,d0			| read it back
729	tstl	d0			| zero?
730	jeq	Lis68020		| yes, we have 68020
731	RELOC(_mmutype, a0)		| no, we have 68030
732	movl	#-1,a0@			| set to reflect 68030 PMMU
733	RELOC(_machineid, a0)
734	movl	#0x80,a1@(MMUCMD)	| set magic cookie
735	movl	a1@(MMUCMD),d0		| read it back
736	btst	#7,d0			| cookie still on?
737	jeq	Lnot370			| no, 360 or 375
738	movl	#0,a1@(MMUCMD)		| clear magic cookie
739	movl	a1@(MMUCMD),d0		| read it back
740	btst	#7,d0			| still on?
741	jeq	Lisa370			| no, must be a 370
742	movl	#5,a0@			| yes, must be a 340
743	jra	Lstart1
744Lnot370:
745	movl	#3,a0@			| type is at least a 360
746	movl	#0,a1@(MMUCMD)		| clear magic cookie2
747	movl	a1@(MMUCMD),d0		| read it back
748	btst	#16,d0			| still on?
749	jeq	Lstart1			| no, must be a 360
750	movl	#6,a0@			| yes, must be a 345/375
751	jra	Lhaspac
752Lisa370:
753	movl	#4,a0@			| set to 370
754Lhaspac:
755	RELOC(_ectype, a0)
756	movl	#-1,a0@			| also has a physical address cache
757	jra	Lstart1
758Lis68020:
759	movl	#1,a1@(MMUCMD)		| a 68020, write HP MMU location
760	movl	a1@(MMUCMD),d0		| read it back
761	btst	#0,d0			| non-zero?
762	jne	Lishpmmu		| yes, we have HP MMU
763	RELOC(_mmutype, a0)
764	movl	#1,a0@			| no, we have PMMU
765	RELOC(_machineid, a0)
766	movl	#1,a0@			| and 330 CPU
767	jra	Lstart1
768Lishpmmu:
769	RELOC(_ectype, a0)		| 320 or 350
770	movl	#1,a0@			| both have a virtual address cache
771	movl	#0x80,a1@(MMUCMD)	| set magic cookie
772	movl	a1@(MMUCMD),d0		| read it back
773	btst	#7,d0			| cookie still on?
774	jeq	Lstart1			| no, just a 320
775	RELOC(_machineid, a0)
776	movl	#2,a0@			| yes, a 350
777
778Lstart1:
779	movl	#0,a1@(MMUCMD)		| clear out MMU again
780/* initialize source/destination control registers for movs */
781	moveq	#FC_USERD,d0		| user space
782	movc	d0,sfc			|   as source
783	movc	d0,dfc			|   and destination of transfers
784
785/*
786 * Allocate kernel segment/page table resources.
787 *	a5 contains the PA of lowest RAM page
788 *	a4 contains the PA of first available page at any time
789 *	d5 contains the VA of first available page at any time
790 *	   (since we assume a zero load point, it is also the size of
791 *	   allocated space at any time)
792 * We assume (i.e. do not check) that the initial page table size
793 * (Sysptsize) is big enough to map everything we allocate here.
794 *
795 * We allocate the IO maps here since the 320/350 MMU registers are
796 * mapped in this range and it would be nice to be able to access them
797 * after the MMU is turned on.
798 */
799	.globl	_Sysseg, _Sysmap, _Sysptmap, _Sysptsize
800	movl	#_end,d5		| end of static kernel text/data
801	addl	#NBPG-1,d5
802	andl	#PG_FRAME,d5		| round to a page
803	movl	d5,a4
804	addl	a5,a4
805/* allocate kernel segment table */
806	RELOC(_Sysseg, a0)
807	movl	d5,a0@			| remember VA for pmap module
808	movl	a4,sp@-			| remember PA for loading MMU
809	addl	#NBPG,a4
810	addl	#NBPG,d5
811/* allocate initial page table pages (including internal IO map) */
812	RELOC(_Sysptsize, a0)
813	movl	a0@,d0			| initial system PT size (pages)
814	addl	#(IIOMAPSIZE+EIOMAPSIZE+NPTEPG-1)/NPTEPG,d0
815					| add pages for IO maps
816	movl	#PGSHIFT,d1
817	lsll	d1,d0			| convert to bytes
818	movl	a4,sp@-			| remember PA for ST load
819	addl	d0,a4
820	addl	d0,d5
821/* allocate kernel page table map */
822	RELOC(_Sysptmap, a0)
823	movl	d5,a0@			| remember VA for pmap module
824	movl	a4,sp@-			| remember PA for PT map load
825	addl	#NBPG,a4
826	addl	#NBPG,d5
827/* compute KVA of Sysptmap; mapped after page table pages */
828	movl	d0,d2			| remember PT size (bytes)
829	moveq	#SG_ISHIFT-PGSHIFT,d1
830	lsll	d1,d0			| page table size serves as seg index
831	RELOC(_Sysmap, a0)
832	movl	d0,a0@			| remember VA for pmap module
833/* initialize ST and PT map: PT pages + PT map */
834	movl	sp@+,a1			| PT map PA
835	movl	sp@+,d4			| start of PT pages
836	movl	sp@+,a0			| ST phys addr
837	lea	a0@(NBPG-4),a2		| (almost) end of ST
838	movl	d4,d3
839	orl	#SG_RW+SG_V,d4		| create proto STE for ST
840	orl	#PG_RW+PG_CI+PG_V,d3	| create proto PTE for PT map
841List1:
842	movl	d4,a0@+
843	movl	d3,a1@+
844	addl	#NBPG,d4
845	addl	#NBPG,d3
846	cmpl	a4,d4			| sleezy, but works ok
847	jcs	List1
848/* initialize ST and PT map: invalidate up to last entry */
849List2:
850	movl	#SG_NV,a0@+
851	movl	#PG_NV,a1@+
852	cmpl	a2,a0
853	jcs	List2
854/*
855 * Portions of the last segment of KVA space (0xFFF00000 - 0xFFFFFFFF)
856 * are mapped for a couple of purposes. 0xFFF00000 for UPAGES is used
857 * for mapping the current process u-area (u + kernel stack).  The
858 * very last page (0xFFFFF000) is mapped to the last physical page of
859 * RAM to give us a region in which PA == VA.  We use this page for
860 * enabling/disabling mapping.
861 */
862	movl	a4,d1			| grab next available for PT page
863	andl	#SG_FRAME,d1		| mask to frame number
864	orl	#SG_RW+SG_V,d1		| RW and valid
865	movl	d1,a0@+			| store in last ST entry
866	movl	a0,a2			| remember addr for PT load
867	andl	#PG_FRAME,d1
868	orl	#PG_RW+PG_V,d1		| convert to PTE
869	movl	d1,a1@+			| store in PT map
870	movl	a4,a0			| physical beginning of PT page
871	lea	a0@(NBPG-4),a1		| (almost) end of page
872Lispt7:
873	movl	#PG_NV,a0@+		| invalidate
874	cmpl	a1,a0
875	jcs	Lispt7
876	movl	#MAXADDR,d1		| get last phys page addr
877	andl	#PG_FRAME,d1
878	orl	#PG_RW+PG_V,d1
879	movl	d1,a0@+			| map to last virt page
880	addl	#NBPG,a4
881	addl	#NBPG,d5
882/* record KVA at which to access current u-area PTEs */
883	RELOC(_Sysmap, a0)
884	movl	a0@,d0			| get system PT address
885	addl	#NPTEPG*NBPG,d0		| end of system PT
886	subl	#HIGHPAGES*4,d0		| back up to first PTE for u-area
887	RELOC(_Umap, a0)
888	movl	d0,a0@			| remember location
889/* initialize page table pages */
890	movl	a2,a0			| end of ST is start of PT
891	addl	d2,a2			| add size to get end of PT
892/* text pages are read-only */
893	clrl	d0			| assume load at VA 0
894	movl	a5,d1			| get load PA
895	andl	#PG_FRAME,d1		| convert to a page frame
896#ifdef KGDB
897	orl	#PG_RW+PG_V,d1		| XXX: RW for now
898#else
899	orl	#PG_RO+PG_V,d1		| create proto PTE
900#endif
901	movl	#_etext,a1		| go til end of text
902Lipt1:
903	movl	d1,a0@+			| load PTE
904	addl	#NBPG,d1		| increment page frame number
905	addl	#NBPG,d0		| and address counter
906	cmpl	a1,d0			| done yet?
907	jcs	Lipt1			| no, keep going
908/* data, bss and dynamic tables are read/write */
909	andl	#PG_FRAME,d1		| mask out old prot bits
910	orl	#PG_RW+PG_V,d1		| mark as valid and RW
911	movl	d5,a1			| go til end of data allocated so far
912	addl	#(UPAGES+1)*NBPG,a1	| and proc0 PT/u-area (to be allocated)
913Lipt2:
914	movl	d1,a0@+			| load PTE
915	addl	#NBPG,d1		| increment page frame number
916	addl	#NBPG,d0		| and address counter
917	cmpl	a1,d0			| done yet?
918	jcs	Lipt2			| no, keep going
919/* invalidate remainder of kernel PT */
920	movl	a2,a1			| end of PT
921Lipt3:
922	movl	#PG_NV,a0@+		| invalidate PTE
923	cmpl	a1,a0			| done yet?
924	jcs	Lipt3			| no, keep going
925/* go back and validate internal IO PTEs at end of allocated PT space */
926	movl	a2,a0			| end of allocated PT space
927	subl	#(IIOMAPSIZE+EIOMAPSIZE)*4,a0	| back up IOMAPSIZE PTEs
928	subl	#EIOMAPSIZE*4,a2	| only initialize internal IO PTEs
929	movl	#INTIOBASE,d1		| physical internal IO base
930	orl	#PG_RW+PG_CI+PG_V,d1	| create proto PTE
931Lipt4:
932	movl	d1,a0@+			| load PTE
933	addl	#NBPG,d1		| increment page frame number
934	cmpl	a2,a0			| done yet?
935	jcs	Lipt4			| no, keep going
936/* record base KVA of IO spaces which are just before Sysmap */
937	RELOC(_Sysmap, a0)
938	movl	a0@,d0			| Sysmap VA
939	subl	#EIOMAPSIZE*NBPG,d0	| back up size of external IO space
940	RELOC(_extiobase, a0)
941	movl	d0,a0@			| and record
942	RELOC(_intiolimit, a0)
943	movl	d0,a0@			| external base is also internal limit
944	subl	#IIOMAPSIZE*NBPG,d0	| back up size of internal IO space
945	RELOC(_intiobase, a0)
946	movl	d0,a0@			| and record
947/* also record base of clock and MMU registers for fast access */
948	addl	#CLKBASE,d0
949	RELOC(_CLKbase, a0)
950	movl	d0,a0@
951	subl	#CLKBASE,d0
952	addl	#MMUBASE,d0
953	RELOC(_MMUbase, a0)
954	movl	d0,a0@
955
956/*
957 * Setup page table for process 0.
958 *
959 * We set up page table access for the kernel via Usrptmap (usrpt)
960 * and access to the u-area itself via Umap (u).  First available
961 * page (VA: d5, PA: a4) is used for proc0 page table.  Next UPAGES
962 * pages following are for u-area.
963 */
964	movl	a4,d0
965	movl	d0,d1
966	andl	#PG_FRAME,d1		| mask to page frame number
967	orl	#PG_RW+PG_V,d1		| RW and valid
968	movl	d1,d4			| remember for later Usrptmap load
969	movl	d0,a0			| base of proc0 PT
970	addl	#NBPG,d0		| plus one page yields base of u-area
971	movl	d0,a2			|   and end of PT
972	addl	#NBPG,d5		| keep VA in sync
973/* invalidate entire page table */
974Liudot1:
975	movl	#PG_NV,a0@+		| invalidate PTE
976	cmpl	a2,a0			| done yet?
977	jcs	Liudot1			| no, keep going
978/* now go back and validate u-area PTEs in PT and in Umap */
979	lea	a0@(-HIGHPAGES*4),a0	| base of PTEs for u-area (p_addr)
980	lea	a0@(UPAGES*4),a1	| end of PTEs for u-area
981	lea	a4@(-HIGHPAGES*4),a3	| u-area PTE base in Umap PT
982	movl	d0,d1			| get base of u-area
983	andl	#PG_FRAME,d1		| mask to page frame number
984	orl	#PG_RW+PG_V,d1		| add valid and writable
985Liudot2:
986	movl	d1,a0@+			| validate p_addr PTE
987	movl	d1,a3@+			| validate u PTE
988	addl	#NBPG,d1		| to next page
989	cmpl	a1,a0			| done yet?
990	jcs	Liudot2			| no, keep going
991/* clear process 0 u-area */
992	addl	#NBPG*UPAGES,d0		| end of u-area
993Lclru1:
994	clrl	a2@+			| clear
995	cmpl	d0,a2			| done yet?
996	jcs	Lclru1			| no, keep going
997	movl	a2,a4			| save phys addr of first avail page
998	RELOC(_proc0paddr, a0)
999	movl	d5,a0@			| save KVA of proc0 u-area
1000	addl	#UPAGES*NBPG,d5		| increment virtual addr as well
1001
1002/*
1003 * Prepare to enable MMU.
1004 * Since the kernel is not mapped logical == physical we must insure
1005 * that when the MMU is turned on, all prefetched addresses (including
1006 * the PC) are valid.  In order guarentee that, we use the last physical
1007 * page (which is conveniently mapped == VA) and load it up with enough
1008 * code to defeat the prefetch, then we execute the jump back to here.
1009 *
1010 * Is this all really necessary, or am I paranoid??
1011 */
1012	RELOC(_Sysseg, a0)		| system segment table addr
1013	movl	a0@,a1			| read value (a KVA)
1014	addl	a5,a1			| convert to PA
1015	RELOC(_mmutype, a0)
1016	tstl	a0@			| HP MMU?
1017	jeq	Lhpmmu2			| yes, skip
1018	RELOC(_protorp, a0)
1019	movl	#0x80000202,a0@		| nolimit + share global + 4 byte PTEs
1020	movl	a1,a0@(4)		| + segtable address
1021	pmove	a0@,srp			| load the supervisor root pointer
1022	movl	#0x80000002,a0@		| reinit upper half for CRP loads
1023	jra	Lstploaddone		| done
1024Lhpmmu2:
1025	movl	a1,d1
1026	moveq	#PGSHIFT,d2
1027	lsrl	d2,d1			| convert to page frame
1028	movl	d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register
1029Lstploaddone:
1030	lea	MAXADDR,a2		| PA of last RAM page
1031	RELOC(Lhighcode, a1)		| addr of high code
1032	RELOC(Lehighcode, a3)		| end addr
1033Lcodecopy:
1034	movw	a1@+,a2@+		| copy a word
1035	cmpl	a3,a1			| done yet?
1036	jcs	Lcodecopy		| no, keep going
1037	jmp	MAXADDR			| go for it!
1038
1039Lhighcode:
1040	RELOC(_mmutype, a0)
1041	tstl	a0@			| HP MMU?
1042	jeq	Lhpmmu3			| yes, skip
1043	movl	#MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD
1044					| enable 68881 and i-cache
1045	movl	#0x82c0aa00,a2@		| value to load TC with
1046	pmove	a2@,tc			| load it
1047	jmp	Lenab1
1048Lhpmmu3:
1049	movl	#0,INTIOBASE+MMUBASE+MMUCMD	| clear external cache
1050	movl	#MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD | turn on MMU
1051	jmp	Lenab1				| jmp to mapped code
1052Lehighcode:
1053
1054/*
1055 * Should be running mapped from this point on
1056 */
1057Lenab1:
1058/* check for internal HP-IB in SYSFLAG */
1059	btst	#5,0xfffffed2		| internal HP-IB?
1060	jeq	Linitmem		| yes, have HP-IB just continue
1061	clrl	_internalhpib		| no, clear associated address
1062/* init mem sizes */
1063Linitmem:
1064	movl	#MAXADDR,d1		| last page
1065	moveq	#PGSHIFT,d2
1066	lsrl	d2,d1			| convert to page (click) number
1067	movl	d1,_maxmem		| save as maxmem
1068	movl	_lowram,d0		| lowram value from ROM via boot
1069	lsrl	d2,d0			| convert to page number
1070	subl	d0,d1			| compute amount of RAM present
1071	movl	d1,_physmem		| and physmem
1072/*
1073 * First we have to select the software page size, then set up the pmap.
1074 * pmap_bootstrap is supposed to be called with mapping off early on
1075 * to set up the kernel VA space.  However, this only works easily if
1076 * you have a kernel PA == VA mapping.  Since we do not, we just set
1077 * up and enable mapping here and then call the bootstrap routine to
1078 * get the pmap module in sync with reality.
1079 */
1080	.globl	_avail_start
1081	lea	tmpstk,sp		| temporary stack
1082	jbsr	_vm_set_page_size	| select software page size
1083	movl	a5,sp@-			| phys load address (assumes VA 0)
1084	movl	a4,sp@-			| first available PA
1085	jbsr	_pmap_bootstrap		| sync up pmap module
1086	addql	#8,sp
1087|	movl	_avail_start,a4		| pmap_bootstrap may need RAM
1088/* set kernel stack, user SP, and initial pcb */
1089	lea	_kstack,a1		| proc0 kernel stack
1090	lea	a1@(UPAGES*NBPG-4),sp	| set kernel stack to end of area
1091	movl	#USRSTACK-4,a2
1092	movl	a2,usp			| init user SP
1093	movl	_proc0paddr,a1		| get proc0 pcb addr
1094	movl	a1,_curpcb		| proc0 is running
1095	clrw	a1@(PCB_FLAGS)		| clear flags
1096#ifdef FPCOPROC
1097	clrl	a1@(PCB_FPCTX)		| ensure null FP context
1098	movl	a1,sp@-
1099	jbsr	_m68881_restore		| restore it (does not kill a1)
1100	addql	#4,sp
1101#endif
1102/* flush TLB and turn on caches */
1103	jbsr	_TBIA			| invalidate TLB
1104	movl	#CACHE_ON,d0
1105	movc	d0,cacr			| clear cache(s)
1106	tstl	_ectype
1107	jeq	Lnocache0
1108	MMUADDR(a0)
1109	orl	#MMU_CEN,a0@(MMUCMD)	| turn on external cache
1110Lnocache0:
1111/* final setup for C code */
1112	movw	#PSL_LOWIPL,sr		| lower SPL
1113	movl	d7,_boothowto		| save reboot flags
1114	movl	d6,_bootdev		|   and boot device
1115	jbsr	_main			| call main()
1116
1117/* proc[1] == init now running here;
1118 * create a null exception frame and return to user mode in icode
1119 */
1120	clrw	sp@-			| vector offset/frame type
1121	clrl	sp@-			| return to icode location 0
1122	movw	#PSL_USER,sp@-		| in user mode
1123	rte
1124
1125/*
1126 * Signal "trampoline" code (18 bytes).  Invoked from RTE setup by sendsig().
1127 *
1128 * Stack looks like:
1129 *
1130 *	sp+0 ->	signal number
1131 *	sp+4	signal specific code
1132 *	sp+8	pointer to signal context frame (scp)
1133 *	sp+12	address of handler
1134 *	sp+16	saved hardware state
1135 *			.
1136 *			.
1137 *	scp+0->	beginning of signal context frame
1138 */
1139	.globl	_sigcode, _esigcode
1140	.data
1141_sigcode:
1142	movl	sp@(12),a0		| signal handler addr	(4 bytes)
1143	jsr	a0@			| call signal handler	(2 bytes)
1144	addql	#4,sp			| pop signo		(2 bytes)
1145	trap	#1			| special syscall entry	(2 bytes)
1146	movl	d0,sp@(4)		| save errno		(4 bytes)
1147	moveq	#1,d0			| syscall == exit	(2 bytes)
1148	trap	#0			| exit(errno)		(2 bytes)
1149	.align	2
1150_esigcode:
1151
1152/*
1153 * Icode is copied out to process 1 to exec init.
1154 * If the exec fails, process 1 exits.
1155 */
1156	.globl	_icode,_szicode
1157	.text
1158_icode:
1159	clrl	sp@-
1160	pea	pc@((argv-.)+2)
1161	pea	pc@((init-.)+2)
1162	clrl	sp@-
1163	moveq	#SYS_execve,d0
1164	trap	#0
1165	moveq	#SYS_exit,d0
1166	trap	#0
1167init:
1168	.asciz	"/sbin/init"
1169	.even
1170argv:
1171	.long	init+6-_icode		| argv[0] = "init" ("/sbin/init" + 6)
1172	.long	eicode-_icode		| argv[1] follows icode after copyout
1173	.long	0
1174eicode:
1175
1176_szicode:
1177	.long	_szicode-_icode
1178
1179/*
1180 * Primitives
1181 */
1182
1183#ifdef GPROF
1184#define	ENTRY(name) \
1185	.globl _/**/name; _/**/name: link a6,#0; jbsr mcount; unlk a6
1186#define ALTENTRY(name, rname) \
1187	ENTRY(name); jra rname+12
1188#else
1189#define	ENTRY(name) \
1190	.globl _/**/name; _/**/name:
1191#define ALTENTRY(name, rname) \
1192	.globl _/**/name; _/**/name:
1193#endif
1194
1195/*
1196 * update profiling information for the user
1197 * addupc(pc, &u.u_prof, ticks)
1198 */
1199ENTRY(addupc)
1200	movl	a2,sp@-			| scratch register
1201	movl	sp@(12),a2		| get &u.u_prof
1202	movl	sp@(8),d0		| get user pc
1203	subl	a2@(8),d0		| pc -= pr->pr_off
1204	jlt	Lauexit			| less than 0, skip it
1205	movl	a2@(12),d1		| get pr->pr_scale
1206	lsrl	#1,d0			| pc /= 2
1207	lsrl	#1,d1			| scale /= 2
1208	mulul	d1,d0			| pc /= scale
1209	moveq	#14,d1
1210	lsrl	d1,d0			| pc >>= 14
1211	bclr	#0,d0			| pc &= ~1
1212	cmpl	a2@(4),d0		| too big for buffer?
1213	jge	Lauexit			| yes, screw it
1214	addl	a2@,d0			| no, add base
1215	movl	d0,sp@-			| push address
1216	jbsr	_fusword		| grab old value
1217	movl	sp@+,a0			| grab address back
1218	cmpl	#-1,d0			| access ok
1219	jeq	Lauerror		| no, skip out
1220	addw	sp@(18),d0		| add tick to current value
1221	movl	d0,sp@-			| push value
1222	movl	a0,sp@-			| push address
1223	jbsr	_susword		| write back new value
1224	addql	#8,sp			| pop params
1225	tstl	d0			| fault?
1226	jeq	Lauexit			| no, all done
1227Lauerror:
1228	clrl	a2@(12)			| clear scale (turn off prof)
1229Lauexit:
1230	movl	sp@+,a2			| restore scratch reg
1231	rts
1232
1233/*
1234 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
1235 *
1236 * Copy a null terminated string from the user address space into
1237 * the kernel address space.
1238 * NOTE: maxlength must be < 64K
1239 */
1240ENTRY(copyinstr)
1241	movl	_curpcb,a0		| current pcb
1242	movl	#Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults
1243	movl	sp@(4),a0		| a0 = fromaddr
1244	movl	sp@(8),a1		| a1 = toaddr
1245	moveq	#0,d0
1246	movw	sp@(14),d0		| d0 = maxlength
1247	jlt	Lcisflt1		| negative count, error
1248	jeq	Lcisdone		| zero count, all done
1249	subql	#1,d0			| set up for dbeq
1250Lcisloop:
1251	movsb	a0@+,d1			| grab a byte
1252	movb	d1,a1@+			| copy it
1253	dbeq	d0,Lcisloop		| if !null and more, continue
1254	jne	Lcisflt2		| ran out of room, error
1255	moveq	#0,d0			| got a null, all done
1256Lcisdone:
1257	tstl	sp@(16)			| return length desired?
1258	jeq	Lcisret			| no, just return
1259	subl	sp@(4),a0		| determine how much was copied
1260	movl	sp@(16),a1		| return location
1261	movl	a0,a1@			| stash it
1262Lcisret:
1263	movl	_curpcb,a0		| current pcb
1264	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
1265	rts
1266Lcisflt1:
1267	moveq	#EFAULT,d0		| copy fault
1268	jra	Lcisdone
1269Lcisflt2:
1270	moveq	#ENAMETOOLONG,d0	| ran out of space
1271	jra	Lcisdone
1272
1273/*
1274 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1275 *
1276 * Copy a null terminated string from the kernel
1277 * address space to the user address space.
1278 * NOTE: maxlength must be < 64K
1279 */
1280ENTRY(copyoutstr)
1281	movl	_curpcb,a0		| current pcb
1282	movl	#Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults
1283	movl	sp@(4),a0		| a0 = fromaddr
1284	movl	sp@(8),a1		| a1 = toaddr
1285	moveq	#0,d0
1286	movw	sp@(14),d0		| d0 = maxlength
1287	jlt	Lcosflt1		| negative count, error
1288	jeq	Lcosdone		| zero count, all done
1289	subql	#1,d0			| set up for dbeq
1290Lcosloop:
1291	movb	a0@+,d1			| grab a byte
1292	movsb	d1,a1@+			| copy it
1293	dbeq	d0,Lcosloop		| if !null and more, continue
1294	jne	Lcosflt2		| ran out of room, error
1295	moveq	#0,d0			| got a null, all done
1296Lcosdone:
1297	tstl	sp@(16)			| return length desired?
1298	jeq	Lcosret			| no, just return
1299	subl	sp@(4),a0		| determine how much was copied
1300	movl	sp@(16),a1		| return location
1301	movl	a0,a1@			| stash it
1302Lcosret:
1303	movl	_curpcb,a0		| current pcb
1304	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
1305	rts
1306Lcosflt1:
1307	moveq	#EFAULT,d0		| copy fault
1308	jra	Lcosdone
1309Lcosflt2:
1310	moveq	#ENAMETOOLONG,d0	| ran out of space
1311	jra	Lcosdone
1312
1313/*
1314 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1315 *
1316 * Copy a null terminated string from one point to another in
1317 * the kernel address space.
1318 * NOTE: maxlength must be < 64K
1319 */
1320ENTRY(copystr)
1321	movl	sp@(4),a0		| a0 = fromaddr
1322	movl	sp@(8),a1		| a1 = toaddr
1323	moveq	#0,d0
1324	movw	sp@(14),d0		| d0 = maxlength
1325	jlt	Lcsflt1			| negative count, error
1326	jeq	Lcsdone			| zero count, all done
1327	subql	#1,d0			| set up for dbeq
1328Lcsloop:
1329	movb	a0@+,a1@+		| copy a byte
1330	dbeq	d0,Lcsloop		| if !null and more, continue
1331	jne	Lcsflt2			| ran out of room, error
1332	moveq	#0,d0			| got a null, all done
1333Lcsdone:
1334	tstl	sp@(16)			| return length desired?
1335	jeq	Lcsret			| no, just return
1336	subl	sp@(4),a0		| determine how much was copied
1337	movl	sp@(16),a1		| return location
1338	movl	a0,a1@			| stash it
1339Lcsret:
1340	rts
1341Lcsflt1:
1342	moveq	#EFAULT,d0		| copy fault
1343	jra	Lcsdone
1344Lcsflt2:
1345	moveq	#ENAMETOOLONG,d0	| ran out of space
1346	jra	Lcsdone
1347
1348/*
1349 * Copyin(from, to, len)
1350 *
1351 * Copy specified amount of data from user space into the kernel.
1352 * NOTE: len must be < 64K
1353 */
1354ENTRY(copyin)
1355	movl	d2,sp@-			| scratch register
1356	movl	_curpcb,a0		| current pcb
1357	movl	#Lciflt,a0@(PCB_ONFAULT) | set up to catch faults
1358	movl	sp@(16),d2		| check count
1359	jlt	Lciflt			| negative, error
1360	jeq	Lcidone			| zero, done
1361	movl	sp@(8),a0		| src address
1362	movl	sp@(12),a1		| dest address
1363	movl	a0,d0
1364	btst	#0,d0			| src address odd?
1365	jeq	Lcieven			| no, go check dest
1366	movsb	a0@+,d1			| yes, get a byte
1367	movb	d1,a1@+			| put a byte
1368	subql	#1,d2			| adjust count
1369	jeq	Lcidone			| exit if done
1370Lcieven:
1371	movl	a1,d0
1372	btst	#0,d0			| dest address odd?
1373	jne	Lcibyte			| yes, must copy by bytes
1374	movl	d2,d0			| no, get count
1375	lsrl	#2,d0			| convert to longwords
1376	jeq	Lcibyte			| no longwords, copy bytes
1377	subql	#1,d0			| set up for dbf
1378Lcilloop:
1379	movsl	a0@+,d1			| get a long
1380	movl	d1,a1@+			| put a long
1381	dbf	d0,Lcilloop		| til done
1382	andl	#3,d2			| what remains
1383	jeq	Lcidone			| all done
1384Lcibyte:
1385	subql	#1,d2			| set up for dbf
1386Lcibloop:
1387	movsb	a0@+,d1			| get a byte
1388	movb	d1,a1@+			| put a byte
1389	dbf	d2,Lcibloop		| til done
1390Lcidone:
1391	moveq	#0,d0			| success
1392Lciexit:
1393	movl	_curpcb,a0		| current pcb
1394	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1395	movl	sp@+,d2			| restore scratch reg
1396	rts
1397Lciflt:
1398	moveq	#EFAULT,d0		| got a fault
1399	jra	Lciexit
1400
1401/*
1402 * Copyout(from, to, len)
1403 *
1404 * Copy specified amount of data from kernel to the user space
1405 * NOTE: len must be < 64K
1406 */
1407ENTRY(copyout)
1408	movl	d2,sp@-			| scratch register
1409	movl	_curpcb,a0		| current pcb
1410	movl	#Lcoflt,a0@(PCB_ONFAULT) | catch faults
1411	movl	sp@(16),d2		| check count
1412	jlt	Lcoflt			| negative, error
1413	jeq	Lcodone			| zero, done
1414	movl	sp@(8),a0		| src address
1415	movl	sp@(12),a1		| dest address
1416	movl	a0,d0
1417	btst	#0,d0			| src address odd?
1418	jeq	Lcoeven			| no, go check dest
1419	movb	a0@+,d1			| yes, get a byte
1420	movsb	d1,a1@+			| put a byte
1421	subql	#1,d2			| adjust count
1422	jeq	Lcodone			| exit if done
1423Lcoeven:
1424	movl	a1,d0
1425	btst	#0,d0			| dest address odd?
1426	jne	Lcobyte			| yes, must copy by bytes
1427	movl	d2,d0			| no, get count
1428	lsrl	#2,d0			| convert to longwords
1429	jeq	Lcobyte			| no longwords, copy bytes
1430	subql	#1,d0			| set up for dbf
1431Lcolloop:
1432	movl	a0@+,d1			| get a long
1433	movsl	d1,a1@+			| put a long
1434	dbf	d0,Lcolloop		| til done
1435	andl	#3,d2			| what remains
1436	jeq	Lcodone			| all done
1437Lcobyte:
1438	subql	#1,d2			| set up for dbf
1439Lcobloop:
1440	movb	a0@+,d1			| get a byte
1441	movsb	d1,a1@+			| put a byte
1442	dbf	d2,Lcobloop		| til done
1443Lcodone:
1444	moveq	#0,d0			| success
1445Lcoexit:
1446	movl	_curpcb,a0		| current pcb
1447	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
1448	movl	sp@+,d2			| restore scratch reg
1449	rts
1450Lcoflt:
1451	moveq	#EFAULT,d0		| got a fault
1452	jra	Lcoexit
1453
1454/*
1455 * non-local gotos
1456 */
1457ENTRY(setjmp)
1458	movl	sp@(4),a0	| savearea pointer
1459	moveml	#0xFCFC,a0@	| save d2-d7/a2-a7
1460	movl	sp@,a0@(48)	| and return address
1461	moveq	#0,d0		| return 0
1462	rts
1463
1464ENTRY(qsetjmp)
1465	movl	sp@(4),a0	| savearea pointer
1466	lea	a0@(40),a0	| skip regs we do not save
1467	movl	a6,a0@+		| save FP
1468	movl	sp,a0@+		| save SP
1469	movl	sp@,a0@		| and return address
1470	moveq	#0,d0		| return 0
1471	rts
1472
1473ENTRY(longjmp)
1474	movl	sp@(4),a0
1475	moveml	a0@+,#0xFCFC
1476	movl	a0@,sp@
1477	moveq	#1,d0
1478	rts
1479
1480/*
1481 * The following primitives manipulate the run queues.
1482 * _whichqs tells which of the 32 queues _qs
1483 * have processes in them.  Setrq puts processes into queues, Remrq
1484 * removes them from queues.  The running process is on no queue,
1485 * other processes are on a queue related to p->p_pri, divided by 4
1486 * actually to shrink the 0-127 range of priorities into the 32 available
1487 * queues.
1488 */
1489
1490	.globl	_whichqs,_qs,_cnt,_panic
1491	.globl	_curproc
1492	.comm	_want_resched,4
1493
1494/*
1495 * Setrq(p)
1496 *
1497 * Call should be made at spl6(), and p->p_stat should be SRUN
1498 */
1499ENTRY(setrq)
1500	movl	sp@(4),a0
1501	tstl	a0@(P_RLINK)
1502	jeq	Lset1
1503	movl	#Lset2,sp@-
1504	jbsr	_panic
1505Lset1:
1506	clrl	d0
1507	movb	a0@(P_PRI),d0
1508	lsrb	#2,d0
1509	movl	_whichqs,d1
1510	bset	d0,d1
1511	movl	d1,_whichqs
1512	lslb	#3,d0
1513	addl	#_qs,d0
1514	movl	d0,a0@(P_LINK)
1515	movl	d0,a1
1516	movl	a1@(P_RLINK),a0@(P_RLINK)
1517	movl	a0,a1@(P_RLINK)
1518	movl	a0@(P_RLINK),a1
1519	movl	a0,a1@(P_LINK)
1520	rts
1521
1522Lset2:
1523	.asciz	"setrq"
1524	.even
1525
1526/*
1527 * Remrq(p)
1528 *
1529 * Call should be made at spl6().
1530 */
1531ENTRY(remrq)
1532	movl	sp@(4),a0
1533	clrl	d0
1534	movb	a0@(P_PRI),d0
1535	lsrb	#2,d0
1536	movl	_whichqs,d1
1537	bclr	d0,d1
1538	jne	Lrem1
1539	movl	#Lrem3,sp@-
1540	jbsr	_panic
1541Lrem1:
1542	movl	d1,_whichqs
1543	movl	a0@(P_LINK),a1
1544	movl	a0@(P_RLINK),a1@(P_RLINK)
1545	movl	a0@(P_RLINK),a1
1546	movl	a0@(P_LINK),a1@(P_LINK)
1547	movl	#_qs,a1
1548	movl	d0,d1
1549	lslb	#3,d1
1550	addl	d1,a1
1551	cmpl	a1@(P_LINK),a1
1552	jeq	Lrem2
1553	movl	_whichqs,d1
1554	bset	d0,d1
1555	movl	d1,_whichqs
1556Lrem2:
1557	clrl	a0@(P_RLINK)
1558	rts
1559
1560Lrem3:
1561	.asciz	"remrq"
1562Lsw0:
1563	.asciz	"swtch"
1564	.even
1565
1566	.globl	_curpcb
1567	.globl	_masterpaddr	| XXX compatibility (debuggers)
1568	.data
1569_masterpaddr:			| XXX compatibility (debuggers)
1570_curpcb:
1571	.long	0
1572pcbflag:
1573	.byte	0		| copy of pcb_flags low byte
1574	.align	2
1575	.comm	nullpcb,SIZEOF_PCB
1576	.text
1577
1578/*
1579 * At exit of a process, do a swtch for the last time.
1580 * The mapping of the pcb at p->p_addr has already been deleted,
1581 * and the memory for the pcb+stack has been freed.
1582 * The ipl is high enough to prevent the memory from being reallocated.
1583 */
1584ENTRY(swtch_exit)
1585	movl	#nullpcb,_curpcb	| save state into garbage pcb
1586	lea	tmpstk,sp		| goto a tmp stack
1587	jra	_swtch
1588
1589/*
1590 * When no processes are on the runq, Swtch branches to idle
1591 * to wait for something to come ready.
1592 */
1593	.globl	Idle
1594Lidle:
1595	stop	#PSL_LOWIPL
1596Idle:
1597idle:
1598	movw	#PSL_HIGHIPL,sr
1599	tstl	_whichqs
1600	jeq	Lidle
1601	movw	#PSL_LOWIPL,sr
1602	jra	Lsw1
1603
1604Lbadsw:
1605	movl	#Lsw0,sp@-
1606	jbsr	_panic
1607	/*NOTREACHED*/
1608
1609/*
1610 * Swtch()
1611 *
1612 * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
1613 * entire ATC.  The effort involved in selective flushing may not be
1614 * worth it, maybe we should just flush the whole thing?
1615 *
1616 * NOTE 2: With the new VM layout we now no longer know if an inactive
1617 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
1618 * bit).  For now, we just always flush the full ATC.
1619 */
1620ENTRY(swtch)
1621	movl	_curpcb,a0		| current pcb
1622	movw	sr,a0@(PCB_PS)		| save sr before changing ipl
1623#ifdef notyet
1624	movl	_curproc,sp@-		| remember last proc running
1625#endif
1626	clrl	_curproc
1627	addql	#1,_cnt+V_SWTCH
1628Lsw1:
1629	/*
1630	 * Find the highest-priority queue that isn't empty,
1631	 * then take the first proc from that queue.
1632	 */
1633	clrl	d0
1634	lea	_whichqs,a0
1635	movl	a0@,d1
1636Lswchk:
1637	btst	d0,d1
1638	jne	Lswfnd
1639	addqb	#1,d0
1640	cmpb	#32,d0
1641	jne	Lswchk
1642	jra	idle
1643Lswfnd:
1644	movw	#PSL_HIGHIPL,sr		| lock out interrupts
1645	movl	a0@,d1			| and check again...
1646	bclr	d0,d1
1647	jeq	Lsw1			| proc moved, rescan
1648	movl	d1,a0@			| update whichqs
1649	moveq	#1,d1			| double check for higher priority
1650	lsll	d0,d1			| process (which may have snuck in
1651	subql	#1,d1			| while we were finding this one)
1652	andl	a0@,d1
1653	jeq	Lswok			| no one got in, continue
1654	movl	a0@,d1
1655	bset	d0,d1			| otherwise put this one back
1656	movl	d1,a0@
1657	jra	Lsw1			| and rescan
1658Lswok:
1659	movl	d0,d1
1660	lslb	#3,d1			| convert queue number to index
1661	addl	#_qs,d1			| locate queue (q)
1662	movl	d1,a1
1663	cmpl	a1@(P_LINK),a1		| anyone on queue?
1664	jeq	Lbadsw			| no, panic
1665	movl	a1@(P_LINK),a0			| p = q->p_link
1666	movl	a0@(P_LINK),a1@(P_LINK)		| q->p_link = p->p_link
1667	movl	a0@(P_LINK),a1			| q = p->p_link
1668	movl	a0@(P_RLINK),a1@(P_RLINK)	| q->p_rlink = p->p_rlink
1669	cmpl	a0@(P_LINK),d1		| anyone left on queue?
1670	jeq	Lsw2			| no, skip
1671	movl	_whichqs,d1
1672	bset	d0,d1			| yes, reset bit
1673	movl	d1,_whichqs
1674Lsw2:
1675	movl	a0,_curproc
1676	clrl	_want_resched
1677#ifdef notyet
1678	movl	sp@+,a1
1679	cmpl	a0,a1			| switching to same proc?
1680	jeq	Lswdone			| yes, skip save and restore
1681#endif
1682	/*
1683	 * Save state of previous process in its pcb.
1684	 */
1685	movl	_curpcb,a1
1686	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1687	movl	usp,a2			| grab USP (a2 has been saved)
1688	movl	a2,a1@(PCB_USP)		| and save it
1689	movl	_CMAP2,a1@(PCB_CMAP2)	| save temporary map PTE
1690#ifdef FPCOPROC
1691	lea	a1@(PCB_FPCTX),a2	| pointer to FP save area
1692	fsave	a2@			| save FP state
1693	tstb	a2@			| null state frame?
1694	jeq	Lswnofpsave		| yes, all done
1695	fmovem	fp0-fp7,a2@(216)	| save FP general registers
1696	fmovem	fpcr/fpsr/fpi,a2@(312)	| save FP control registers
1697Lswnofpsave:
1698#endif
1699
1700#ifdef DIAGNOSTIC
1701	tstl	a0@(P_WCHAN)
1702	jne	Lbadsw
1703	cmpb	#SRUN,a0@(P_STAT)
1704	jne	Lbadsw
1705#endif
1706	clrl	a0@(P_RLINK)		| clear back link
1707	movl	a0@(P_ADDR),a1		| get p_addr
1708	movl	a1,_curpcb
1709	movb	a1@(PCB_FLAGS+1),pcbflag | copy of pcb_flags low byte
1710
1711	/* see if pmap_activate needs to be called; should remove this */
1712	movl	a0@(P_VMSPACE),a0	| vmspace = p->p_vmspace
1713#ifdef DIAGNOSTIC
1714	tstl	a0			| map == VM_MAP_NULL?
1715	jeq	Lbadsw			| panic
1716#endif
1717	lea	a0@(VM_PMAP),a0		| pmap = &vmspace.vm_pmap
1718	tstl	a0@(PM_STCHG)		| pmap->st_changed?
1719	jeq	Lswnochg		| no, skip
1720	pea	a1@			| push pcb (at p_addr)
1721	pea	a0@			| push pmap
1722	jbsr	_pmap_activate		| pmap_activate(pmap, pcb)
1723	addql	#8,sp
1724	movl	_curpcb,a1		| restore p_addr
1725Lswnochg:
1726
1727#ifdef PROFTIMER
1728#ifdef notdef
1729	movw	#SPL6,sr		| protect against clock interrupts
1730#endif
1731	bclr	#0,_profon		| clear user profiling bit, was set?
1732	jeq	Lskipoff		| no, clock off or doing kernel only
1733#ifdef GPROF
1734	tstb	_profon			| kernel profiling also enabled?
1735	jlt	Lskipoff		| yes, nothing more to do
1736#endif
1737	CLKADDR(a0)
1738	movb	#0,a0@(CLKCR2)		| no, just user, select CR3
1739	movb	#0,a0@(CLKCR3)		| and turn it off
1740Lskipoff:
1741#endif
1742	movl	#PGSHIFT,d1
1743	movl	a1,d0
1744	lsrl	d1,d0			| convert p_addr to page number
1745	lsll	#2,d0			| and now to Systab offset
1746	addl	_Sysmap,d0		| add Systab base to get PTE addr
1747#ifdef notdef
1748	movw	#PSL_HIGHIPL,sr		| go crit while changing PTEs
1749#endif
1750	lea	tmpstk,sp		| now goto a tmp stack for NMI
1751	movl	d0,a0			| address of new context
1752	movl	_Umap,a2		| address of PTEs for kstack
1753	moveq	#UPAGES-1,d0		| sizeof kstack
1754Lres1:
1755	movl	a0@+,d1			| get PTE
1756	andl	#~PG_PROT,d1		| mask out old protection
1757	orl	#PG_RW+PG_V,d1		| ensure valid and writable
1758	movl	d1,a2@+			| load it up
1759	dbf	d0,Lres1		| til done
1760	movl	#CACHE_CLR,d0
1761	movc	d0,cacr			| invalidate cache(s)
1762#if defined(HP330) || defined(HP360) || defined(HP370)
1763	tstl	_mmutype		| HP MMU?
1764	jeq	Lhpmmu4			| yes, skip
1765	pflusha				| flush entire TLB
1766	movl	a1@(PCB_USTP),d0	| get USTP
1767	moveq	#PGSHIFT,d1
1768	lsll	d1,d0			| convert to addr
1769	lea	_protorp,a0		| CRP prototype
1770	movl	d0,a0@(4)		| stash USTP
1771	pmove	a0@,crp			| load new user root pointer
1772	jra	Lcxswdone		| thats it
1773Lhpmmu4:
1774#endif
1775#if defined(HP320) || defined(HP350)
1776	MMUADDR(a0)
1777	movl	a0@(MMUTBINVAL),d1	| invalidate TLB
1778	tstl	_ectype			| got external VAC?
1779	jle	Lnocache1		| no, skip
1780	andl	#~MMU_CEN,a0@(MMUCMD)	| toggle cache enable
1781	orl	#MMU_CEN,a0@(MMUCMD)	| to clear data cache
1782Lnocache1:
1783	movl	a1@(PCB_USTP),a0@(MMUUSTP) | context switch
1784#endif
1785Lcxswdone:
1786	movl	a1@(PCB_CMAP2),_CMAP2	| reload tmp map
1787	moveml	a1@(PCB_REGS),#0xFCFC	| and registers
1788	movl	a1@(PCB_USP),a0
1789	movl	a0,usp			| and USP
1790#ifdef PROFTIMER
1791	tstl	a1@(U_PROFSCALE)	| process being profiled?
1792	jeq	Lskipon			| no, do nothing
1793	orb	#1,_profon		| turn on user profiling bit
1794#ifdef GPROF
1795	jlt	Lskipon			| already profiling kernel, all done
1796#endif
1797	CLKADDR(a0)
1798	movl	_profint,d1		| profiling interval
1799	subql	#1,d1			|   adjusted
1800	movepw	d1,a0@(CLKMSB3)		| set interval
1801	movb	#0,a0@(CLKCR2)		| select CR3
1802	movb	#64,a0@(CLKCR3)		| turn it on
1803Lskipon:
1804#endif
1805#ifdef FPCOPROC
1806	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1807	tstb	a0@			| null state frame?
1808	jeq	Lresfprest		| yes, easy
1809	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
1810	fmovem	a0@(216),fp0-fp7	| restore FP general registers
1811Lresfprest:
1812	frestore a0@			| restore state
1813#endif
1814	movw	a1@(PCB_PS),sr		| no, restore PS
1815	moveq	#1,d0			| return 1 (for alternate returns)
1816	rts
1817
1818/*
1819 * savectx(pcb, altreturn)
1820 * Update pcb, saving current processor state and arranging
1821 * for alternate return ala longjmp in swtch if altreturn is true.
1822 */
1823ENTRY(savectx)
1824	movl	sp@(4),a1
1825	movw	sr,a1@(PCB_PS)
1826	movl	usp,a0			| grab USP
1827	movl	a0,a1@(PCB_USP)		| and save it
1828	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
1829	movl	_CMAP2,a1@(PCB_CMAP2)	| save temporary map PTE
1830#ifdef FPCOPROC
1831	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
1832	fsave	a0@			| save FP state
1833	tstb	a0@			| null state frame?
1834	jeq	Lsvnofpsave		| yes, all done
1835	fmovem	fp0-fp7,a0@(216)	| save FP general registers
1836	fmovem	fpcr/fpsr/fpi,a0@(312)	| save FP control registers
1837Lsvnofpsave:
1838#endif
1839	tstl	sp@(8)			| altreturn?
1840	jeq	Lsavedone
1841	movl	sp,d0			| relocate current sp relative to a1
1842	subl	#_kstack,d0		|   (sp is relative to kstack):
1843	addl	d0,a1			|   a1 += sp - kstack;
1844	movl	sp@,a1@			| write return pc at (relocated) sp@
1845Lsavedone:
1846	moveq	#0,d0			| return 0
1847	rts
1848
1849/*
1850 * {fu,su},{byte,sword,word}
1851 */
1852ALTENTRY(fuiword, _fuword)
1853ENTRY(fuword)
1854	movl	sp@(4),a0		| address to read
1855	movl	_curpcb,a1		| current pcb
1856	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1857	movsl	a0@,d0			| do read from user space
1858	jra	Lfsdone
1859
1860ENTRY(fusword)
1861	movl	sp@(4),a0
1862	movl	_curpcb,a1		| current pcb
1863	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1864	moveq	#0,d0
1865	movsw	a0@,d0			| do read from user space
1866	jra	Lfsdone
1867
1868ALTENTRY(fuibyte, _fubyte)
1869ENTRY(fubyte)
1870	movl	sp@(4),a0		| address to read
1871	movl	_curpcb,a1		| current pcb
1872	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1873	moveq	#0,d0
1874	movsb	a0@,d0			| do read from user space
1875	jra	Lfsdone
1876
1877Lfserr:
1878	moveq	#-1,d0			| error indicator
1879Lfsdone:
1880	clrl	a1@(PCB_ONFAULT) 	| clear fault address
1881	rts
1882
1883ALTENTRY(suiword, _suword)
1884ENTRY(suword)
1885	movl	sp@(4),a0		| address to write
1886	movl	sp@(8),d0		| value to put there
1887	movl	_curpcb,a1		| current pcb
1888	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1889	movsl	d0,a0@			| do write to user space
1890	moveq	#0,d0			| indicate no fault
1891	jra	Lfsdone
1892
1893ENTRY(susword)
1894	movl	sp@(4),a0		| address to write
1895	movw	sp@(10),d0		| value to put there
1896	movl	_curpcb,a1		| current pcb
1897	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1898	movsw	d0,a0@			| do write to user space
1899	moveq	#0,d0			| indicate no fault
1900	jra	Lfsdone
1901
1902ALTENTRY(suibyte, _subyte)
1903ENTRY(subyte)
1904	movl	sp@(4),a0		| address to write
1905	movb	sp@(11),d0		| value to put there
1906	movl	_curpcb,a1		| current pcb
1907	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
1908	movsb	d0,a0@			| do write to user space
1909	moveq	#0,d0			| indicate no fault
1910	jra	Lfsdone
1911
1912/*
1913 * Copy 1 relocation unit (NBPG bytes)
1914 * from user virtual address to physical address
1915 */
1916ENTRY(copyseg)
1917	movl	_curpcb,a1			| current pcb
1918	movl	#Lcpydone,a1@(PCB_ONFAULT)	| where to return to on a fault
1919	movl	sp@(8),d0			| destination page number
1920	moveq	#PGSHIFT,d1
1921	lsll	d1,d0				| convert to address
1922	orl	#PG_CI+PG_RW+PG_V,d0		| make sure valid and writable
1923	movl	_CMAP2,a0
1924	movl	_CADDR2,sp@-			| destination kernel VA
1925	movl	d0,a0@				| load in page table
1926	jbsr	_TBIS				| invalidate any old mapping
1927	addql	#4,sp
1928	movl	_CADDR2,a1			| destination addr
1929	movl	sp@(4),a0			| source addr
1930	movl	#NBPG/4-1,d0			| count
1931Lcpyloop:
1932	movsl	a0@+,d1				| read longword
1933	movl	d1,a1@+				| write longword
1934	dbf	d0,Lcpyloop			| continue until done
1935Lcpydone:
1936	movl	_curpcb,a1			| current pcb
1937	clrl	a1@(PCB_ONFAULT) 		| clear error catch
1938	rts
1939
1940/*
1941 * Copy 1 relocation unit (NBPG bytes)
1942 * from physical address to physical address
1943 */
1944ENTRY(physcopyseg)
1945	movl	sp@(4),d0			| source page number
1946	moveq	#PGSHIFT,d1
1947	lsll	d1,d0				| convert to address
1948	orl	#PG_CI+PG_RW+PG_V,d0		| make sure valid and writable
1949	movl	_CMAP1,a0
1950	movl	d0,a0@				| load in page table
1951	movl	_CADDR1,sp@-			| destination kernel VA
1952	jbsr	_TBIS				| invalidate any old mapping
1953	addql	#4,sp
1954
1955	movl	sp@(8),d0			| destination page number
1956	moveq	#PGSHIFT,d1
1957	lsll	d1,d0				| convert to address
1958	orl	#PG_CI+PG_RW+PG_V,d0		| make sure valid and writable
1959	movl	_CMAP2,a0
1960	movl	d0,a0@				| load in page table
1961	movl	_CADDR2,sp@-			| destination kernel VA
1962	jbsr	_TBIS				| invalidate any old mapping
1963	addql	#4,sp
1964
1965	movl	_CADDR1,a0			| source addr
1966	movl	_CADDR2,a1			| destination addr
1967	movl	#NBPG/4-1,d0			| count
1968Lpcpy:
1969	movl	a0@+,a1@+			| copy longword
1970	dbf	d0,Lpcpy			| continue until done
1971	rts
1972
1973/*
1974 * zero out physical memory
1975 * specified in relocation units (NBPG bytes)
1976 */
1977ENTRY(clearseg)
1978	movl	sp@(4),d0			| destination page number
1979	moveq	#PGSHIFT,d1
1980	lsll	d1,d0				| convert to address
1981	orl	#PG_CI+PG_RW+PG_V,d0		| make sure valid and writable
1982	movl	_CMAP1,a0
1983	movl	_CADDR1,sp@-			| destination kernel VA
1984	movl	d0,a0@				| load in page map
1985	jbsr	_TBIS				| invalidate any old mapping
1986	addql	#4,sp
1987	movl	_CADDR1,a1			| destination addr
1988	movl	#NBPG/4-1,d0			| count
1989/* simple clear loop is fastest on 68020 */
1990Lclrloop:
1991	clrl	a1@+				| clear a longword
1992	dbf	d0,Lclrloop			| continue til done
1993	rts
1994
1995/*
1996 * Invalidate entire TLB.
1997 */
1998ENTRY(TBIA)
1999__TBIA:
2000#if defined(HP330) || defined(HP360) || defined(HP370)
2001	tstl	_mmutype		| HP MMU?
2002	jeq	Lhpmmu6			| yes, skip
2003	pflusha				| flush entire TLB
2004#if defined(HP360) || defined(HP370)
2005	jpl	Lmc68851a		| 68851 implies no d-cache
2006	movl	#DC_CLEAR,d0
2007	movc	d0,cacr			| invalidate on-chip d-cache
2008Lmc68851a:
2009#endif
2010	rts
2011Lhpmmu6:
2012#endif
2013#if defined(HP320) || defined(HP350)
2014	MMUADDR(a0)
2015	movl	a0@(MMUTBINVAL),sp@-	| do not ask me, this
2016	addql	#4,sp			|   is how hpux does it
2017#ifdef DEBUG
2018	tstl	fullcflush
2019	jne	__DCIA			| XXX: invalidate entire cache
2020#endif
2021#endif
2022	rts
2023
2024/*
2025 * Invalidate any TLB entry for given VA (TB Invalidate Single)
2026 */
2027ENTRY(TBIS)
2028#ifdef DEBUG
2029	tstl	fulltflush		| being conservative?
2030	jne	__TBIA			| yes, flush entire TLB
2031#endif
2032#if defined(HP330) || defined(HP360) || defined(HP370)
2033	tstl	_mmutype		| HP MMU?
2034	jeq	Lhpmmu5			| yes, skip
2035	movl	sp@(4),a0		| get addr to flush
2036#if defined(HP360) || defined(HP370)
2037	jpl	Lmc68851b		| is 68851?
2038	pflush	#0,#0,a0@		| flush address from both sides
2039	movl	#DC_CLEAR,d0
2040	movc	d0,cacr			| invalidate on-chip data cache
2041	rts
2042Lmc68851b:
2043#endif
2044	pflushs	#0,#0,a0@		| flush address from both sides
2045	rts
2046Lhpmmu5:
2047#endif
2048#if defined(HP320) || defined(HP350)
2049	movl	sp@(4),d0		| VA to invalidate
2050	bclr	#0,d0			| ensure even
2051	movl	d0,a0
2052	movw	sr,d1			| go critical
2053	movw	#PSL_HIGHIPL,sr		|   while in purge space
2054	moveq	#FC_PURGE,d0		| change address space
2055	movc	d0,dfc			|   for destination
2056	moveq	#0,d0			| zero to invalidate?
2057	movsl	d0,a0@			| hit it
2058	moveq	#FC_USERD,d0		| back to old
2059	movc	d0,dfc			|   address space
2060	movw	d1,sr			| restore IPL
2061#endif
2062	rts
2063
2064/*
2065 * Invalidate supervisor side of TLB
2066 */
2067ENTRY(TBIAS)
2068#ifdef DEBUG
2069	tstl	fulltflush		| being conservative?
2070	jne	__TBIA			| yes, flush everything
2071#endif
2072#if defined(HP330) || defined(HP360) || defined(HP370)
2073	tstl	_mmutype		| HP MMU?
2074	jeq	Lhpmmu7			| yes, skip
2075#if defined(HP360) || defined(HP370)
2076	jpl	Lmc68851c		| 68851?
2077	pflush #4,#4			| flush supervisor TLB entries
2078	movl	#DC_CLEAR,d0
2079	movc	d0,cacr			| invalidate on-chip d-cache
2080	rts
2081Lmc68851c:
2082#endif
2083	pflushs #4,#4			| flush supervisor TLB entries
2084	rts
2085Lhpmmu7:
2086#endif
2087#if defined(HP320) || defined(HP350)
2088	MMUADDR(a0)
2089	movl	#0x8000,d0		| more
2090	movl	d0,a0@(MMUTBINVAL)	|   HP magic
2091#ifdef DEBUG
2092	tstl	fullcflush
2093	jne	__DCIS			| XXX: invalidate entire sup. cache
2094#endif
2095#endif
2096	rts
2097
2098/*
2099 * Invalidate user side of TLB
2100 */
2101ENTRY(TBIAU)
2102#ifdef DEBUG
2103	tstl	fulltflush		| being conservative?
2104	jne	__TBIA			| yes, flush everything
2105#endif
2106#if defined(HP330) || defined(HP360) || defined(HP370)
2107	tstl	_mmutype		| HP MMU?
2108	jeq	Lhpmmu8			| yes, skip
2109#if defined(HP360) || defined(HP370)
2110	jpl	Lmc68851d		| 68851?
2111	pflush	#0,#4			| flush user TLB entries
2112	movl	#DC_CLEAR,d0
2113	movc	d0,cacr			| invalidate on-chip d-cache
2114	rts
2115Lmc68851d:
2116#endif
2117	pflushs	#0,#4			| flush user TLB entries
2118	rts
2119Lhpmmu8:
2120#endif
2121#if defined(HP320) || defined(HP350)
2122	MMUADDR(a0)
2123	moveq	#0,d0			| more
2124	movl	d0,a0@(MMUTBINVAL)	|   HP magic
2125#ifdef DEBUG
2126	tstl	fullcflush
2127	jne	__DCIU			| XXX: invalidate entire user cache
2128#endif
2129#endif
2130	rts
2131
2132/*
2133 * Invalidate instruction cache
2134 */
2135ENTRY(ICIA)
2136	movl	#IC_CLEAR,d0
2137	movc	d0,cacr			| invalidate i-cache
2138	rts
2139
2140/*
2141 * Invalidate data cache.
2142 * HP external cache allows for invalidation of user/supervisor portions.
2143 * NOTE: we do not flush 68030 on-chip cache as there are no aliasing
2144 * problems with DC_WA.  The only cases we have to worry about are context
2145 * switch and TLB changes, both of which are handled "in-line" in resume
2146 * and TBI*.
2147 */
2148ENTRY(DCIA)
2149__DCIA:
2150#if defined(HP320) || defined(HP350)
2151	tstl	_ectype			| got external VAC?
2152	jle	Lnocache2		| no, all done
2153	MMUADDR(a0)
2154	andl	#~MMU_CEN,a0@(MMUCMD)	| disable cache in MMU control reg
2155	orl	#MMU_CEN,a0@(MMUCMD)	| reenable cache in MMU control reg
2156Lnocache2:
2157#endif
2158	rts
2159
2160ENTRY(DCIS)
2161__DCIS:
2162#if defined(HP320) || defined(HP350)
2163	tstl	_ectype			| got external VAC?
2164	jle	Lnocache3		| no, all done
2165	MMUADDR(a0)
2166	movl	a0@(MMUSSTP),d0		| read the supervisor STP
2167	movl	d0,a0@(MMUSSTP)		| write it back
2168Lnocache3:
2169#endif
2170	rts
2171
2172ENTRY(DCIU)
2173__DCIU:
2174#if defined(HP320) || defined(HP350)
2175	tstl	_ectype			| got external VAC?
2176	jle	Lnocache4		| no, all done
2177	MMUADDR(a0)
2178	movl	a0@(MMUUSTP),d0		| read the user STP
2179	movl	d0,a0@(MMUUSTP)		| write it back
2180Lnocache4:
2181#endif
2182	rts
2183
2184ENTRY(PCIA)
2185#if defined(HP360) || defined(HP370)
2186	movl	#DC_CLEAR,d0
2187	movc	d0,cacr			| invalidate on-chip d-cache
2188	tstl	_ectype			| got external PAC?
2189	jge	Lnocache6		| no, all done
2190	MMUADDR(a0)
2191	andl	#~MMU_CEN,a0@(MMUCMD)	| disable cache in MMU control reg
2192	orl	#MMU_CEN,a0@(MMUCMD)	| reenable cache in MMU control reg
2193Lnocache6:
2194#endif
2195	rts
2196
2197ENTRY(ecacheon)
2198	tstl	_ectype
2199	jeq	Lnocache7
2200	MMUADDR(a0)
2201	orl	#MMU_CEN,a0@(MMUCMD)
2202Lnocache7:
2203	rts
2204
2205ENTRY(ecacheoff)
2206	tstl	_ectype
2207	jeq	Lnocache8
2208	MMUADDR(a0)
2209	andl	#~MMU_CEN,a0@(MMUCMD)
2210Lnocache8:
2211	rts
2212
2213/*
2214 * Get callers current SP value.
2215 * Note that simply taking the address of a local variable in a C function
2216 * doesn't work because callee saved registers may be outside the stack frame
2217 * defined by A6 (e.g. GCC generated code).
2218 */
2219	.globl	_getsp
2220_getsp:
2221	movl	sp,d0			| get current SP
2222	addql	#4,d0			| compensate for return address
2223	rts
2224
2225	.globl	_getsfc, _getdfc
2226_getsfc:
2227	movc	sfc,d0
2228	rts
2229_getdfc:
2230	movc	dfc,d0
2231	rts
2232
2233/*
2234 * Load a new user segment table pointer.
2235 */
2236ENTRY(loadustp)
2237#if defined(HP330) || defined(HP360) || defined(HP370)
2238	tstl	_mmutype		| HP MMU?
2239	jeq	Lhpmmu9			| yes, skip
2240	movl	sp@(4),d0		| new USTP
2241	moveq	#PGSHIFT,d1
2242	lsll	d1,d0			| convert to addr
2243	lea	_protorp,a0		| CRP prototype
2244	movl	d0,a0@(4)		| stash USTP
2245	pmove	a0@,crp			| load root pointer
2246	movl	#DC_CLEAR,d0
2247	movc	d0,cacr			| invalidate on-chip d-cache
2248	rts				|   since pmove flushes TLB
2249Lhpmmu9:
2250#endif
2251#if defined(HP320) || defined(HP350)
2252	MMUADDR(a0)
2253	movl	sp@(4),a0@(MMUUSTP)	| load a new USTP
2254#endif
2255	rts
2256
2257/*
2258 * Flush any hardware context associated with given USTP.
2259 * Only does something for HP330 where we must flush RPT
2260 * and ATC entries in PMMU.
2261 */
2262ENTRY(flushustp)
2263#if defined(HP330)
2264	tstl	_mmutype		| 68851 PMMU?
2265	jle	Lnot68851		| no, nothing to do
2266	movl	sp@(4),d0		| get USTP to flush
2267	moveq	#PGSHIFT,d1
2268	lsll	d1,d0			| convert to address
2269	movl	d0,_protorp+4		| stash USTP
2270	pflushr	_protorp		| flush RPT/TLB entries
2271Lnot68851:
2272#endif
2273	rts
2274
2275ENTRY(ploadw)
2276#if defined(HP330) || defined(HP360) || defined(HP370)
2277	movl	sp@(4),a0		| address to load
2278	ploadw	#1,a0@			| pre-load translation
2279#endif
2280	rts
2281
2282/*
2283 * Set processor priority level calls.  Most are implemented with
2284 * inline asm expansions.  However, spl0 requires special handling
2285 * as we need to check for our emulated software interrupts.
2286 */
2287
2288ENTRY(spl0)
2289	moveq	#0,d0
2290	movw	sr,d0			| get old SR for return
2291	movw	#PSL_LOWIPL,sr		| restore new SR
2292	tstb	_ssir			| software interrupt pending?
2293	jeq	Lspldone		| no, all done
2294	subql	#4,sp			| make room for RTE frame
2295	movl	sp@(4),sp@(2)		| position return address
2296	clrw	sp@(6)			| set frame type 0
2297	movw	#PSL_LOWIPL,sp@		| and new SR
2298	jra	Lgotsir			| go handle it
2299Lspldone:
2300	rts
2301
2302ENTRY(_insque)
2303	movw	sr,d0
2304	movw	#PSL_HIGHIPL,sr		| atomic
2305	movl	sp@(8),a0		| where to insert (after)
2306	movl	sp@(4),a1		| element to insert (e)
2307	movl	a0@,a1@			| e->next = after->next
2308	movl	a0,a1@(4)		| e->prev = after
2309	movl	a1,a0@			| after->next = e
2310	movl	a1@,a0
2311	movl	a1,a0@(4)		| e->next->prev = e
2312	movw	d0,sr
2313	rts
2314
2315ENTRY(_remque)
2316	movw	sr,d0
2317	movw	#PSL_HIGHIPL,sr		| atomic
2318	movl	sp@(4),a0		| element to remove (e)
2319	movl	a0@,a1
2320	movl	a0@(4),a0
2321	movl	a0,a1@(4)		| e->next->prev = e->prev
2322	movl	a1,a0@			| e->prev->next = e->next
2323	movw	d0,sr
2324	rts
2325
2326/*
2327 * bzero(addr, count)
2328 */
2329ALTENTRY(blkclr, _bzero)
2330ENTRY(bzero)
2331	movl	sp@(4),a0	| address
2332	movl	sp@(8),d0	| count
2333	jeq	Lbzdone		| if zero, nothing to do
2334	movl	a0,d1
2335	btst	#0,d1		| address odd?
2336	jeq	Lbzeven		| no, can copy words
2337	clrb	a0@+		| yes, zero byte to get to even boundary
2338	subql	#1,d0		| decrement count
2339	jeq	Lbzdone		| none left, all done
2340Lbzeven:
2341	movl	d0,d1
2342	andl	#31,d0
2343	lsrl	#5,d1		| convert count to 8*longword count
2344	jeq	Lbzbyte		| no such blocks, zero byte at a time
2345Lbzloop:
2346	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
2347	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
2348	subql	#1,d1		| one more block zeroed
2349	jne	Lbzloop		| more to go, do it
2350	tstl	d0		| partial block left?
2351	jeq	Lbzdone		| no, all done
2352Lbzbyte:
2353	clrb	a0@+
2354	subql	#1,d0		| one more byte cleared
2355	jne	Lbzbyte		| more to go, do it
2356Lbzdone:
2357	rts
2358
2359/*
2360 * strlen(str)
2361 */
2362ENTRY(strlen)
2363	moveq	#-1,d0
2364	movl	sp@(4),a0	| string
2365Lslloop:
2366	addql	#1,d0		| increment count
2367	tstb	a0@+		| null?
2368	jne	Lslloop		| no, keep going
2369	rts
2370
2371/*
2372 * bcmp(s1, s2, len)
2373 *
2374 * WARNING!  This guy only works with counts up to 64K
2375 */
2376ENTRY(bcmp)
2377	movl	sp@(4),a0		| string 1
2378	movl	sp@(8),a1		| string 2
2379	moveq	#0,d0
2380	movw	sp@(14),d0		| length
2381	jeq	Lcmpdone		| if zero, nothing to do
2382	subqw	#1,d0			| set up for DBcc loop
2383Lcmploop:
2384	cmpmb	a0@+,a1@+		| equal?
2385	dbne	d0,Lcmploop		| yes, keep going
2386	addqw	#1,d0			| +1 gives zero on match
2387Lcmpdone:
2388	rts
2389
2390/*
2391 * {ov}bcopy(from, to, len)
2392 *
2393 * Works for counts up to 128K.
2394 */
2395ALTENTRY(ovbcopy, _bcopy)
2396ENTRY(bcopy)
2397	movl	sp@(12),d0		| get count
2398	jeq	Lcpyexit		| if zero, return
2399	movl	sp@(4),a0		| src address
2400	movl	sp@(8),a1		| dest address
2401	cmpl	a1,a0			| src before dest?
2402	jlt	Lcpyback		| yes, copy backwards (avoids overlap)
2403	movl	a0,d1
2404	btst	#0,d1			| src address odd?
2405	jeq	Lcfeven			| no, go check dest
2406	movb	a0@+,a1@+		| yes, copy a byte
2407	subql	#1,d0			| update count
2408	jeq	Lcpyexit		| exit if done
2409Lcfeven:
2410	movl	a1,d1
2411	btst	#0,d1			| dest address odd?
2412	jne	Lcfbyte			| yes, must copy by bytes
2413	movl	d0,d1			| no, get count
2414	lsrl	#2,d1			| convert to longwords
2415	jeq	Lcfbyte			| no longwords, copy bytes
2416	subql	#1,d1			| set up for dbf
2417Lcflloop:
2418	movl	a0@+,a1@+		| copy longwords
2419	dbf	d1,Lcflloop		| til done
2420	andl	#3,d0			| get remaining count
2421	jeq	Lcpyexit		| done if none
2422Lcfbyte:
2423	subql	#1,d0			| set up for dbf
2424Lcfbloop:
2425	movb	a0@+,a1@+		| copy bytes
2426	dbf	d0,Lcfbloop		| til done
2427Lcpyexit:
2428	rts
2429Lcpyback:
2430	addl	d0,a0			| add count to src
2431	addl	d0,a1			| add count to dest
2432	movl	a0,d1
2433	btst	#0,d1			| src address odd?
2434	jeq	Lcbeven			| no, go check dest
2435	movb	a0@-,a1@-		| yes, copy a byte
2436	subql	#1,d0			| update count
2437	jeq	Lcpyexit		| exit if done
2438Lcbeven:
2439	movl	a1,d1
2440	btst	#0,d1			| dest address odd?
2441	jne	Lcbbyte			| yes, must copy by bytes
2442	movl	d0,d1			| no, get count
2443	lsrl	#2,d1			| convert to longwords
2444	jeq	Lcbbyte			| no longwords, copy bytes
2445	subql	#1,d1			| set up for dbf
2446Lcblloop:
2447	movl	a0@-,a1@-		| copy longwords
2448	dbf	d1,Lcblloop		| til done
2449	andl	#3,d0			| get remaining count
2450	jeq	Lcpyexit		| done if none
2451Lcbbyte:
2452	subql	#1,d0			| set up for dbf
2453Lcbbloop:
2454	movb	a0@-,a1@-		| copy bytes
2455	dbf	d0,Lcbbloop		| til done
2456	rts
2457
2458/*
2459 * Emulate fancy VAX string operations:
2460 *	scanc(count, startc, table, mask)
2461 *	skpc(mask, count, startc)
2462 *	locc(mask, count, startc)
2463 */
2464ENTRY(scanc)
2465	movl	sp@(4),d0	| get length
2466	jeq	Lscdone		| nothing to do, return
2467	movl	sp@(8),a0	| start of scan
2468	movl	sp@(12),a1	| table to compare with
2469	movb	sp@(19),d1	| and mask to use
2470	movw	d2,sp@-		| need a scratch register
2471	clrw	d2		| clear it out
2472	subqw	#1,d0		| adjust for dbra
2473Lscloop:
2474	movb	a0@+,d2		| get character
2475	movb	a1@(0,d2:w),d2	| get table entry
2476	andb	d1,d2		| mask it
2477	dbne	d0,Lscloop	| keep going til no more or non-zero
2478	addqw	#1,d0		| overshot by one
2479	movw	sp@+,d2		| restore scratch
2480Lscdone:
2481	rts
2482
2483ENTRY(skpc)
2484	movl	sp@(8),d0	| get length
2485	jeq	Lskdone		| nothing to do, return
2486	movb	sp@(7),d1	| mask to use
2487	movl	sp@(12),a0	| where to start
2488	subqw	#1,d0		| adjust for dbcc
2489Lskloop:
2490	cmpb	a0@+,d1		| compate with mask
2491	dbne	d0,Lskloop	| keep going til no more or zero
2492	addqw	#1,d0		| overshot by one
2493Lskdone:
2494	rts
2495
2496ENTRY(locc)
2497	movl	sp@(8),d0	| get length
2498	jeq	Llcdone		| nothing to do, return
2499	movb	sp@(7),d1	| mask to use
2500	movl	sp@(12),a0	| where to start
2501	subqw	#1,d0		| adjust for dbcc
2502Llcloop:
2503	cmpb	a0@+,d1		| compate with mask
2504	dbeq	d0,Llcloop	| keep going til no more or non-zero
2505	addqw	#1,d0		| overshot by one
2506Llcdone:
2507	rts
2508
2509/*
2510 * Emulate VAX FFS (find first set) instruction.
2511 */
2512ENTRY(ffs)
2513	moveq	#-1,d0
2514	movl	sp@(4),d1
2515	jeq	Lffsdone
2516Lffsloop:
2517	addql	#1,d0
2518	btst	d0,d1
2519	jeq	Lffsloop
2520Lffsdone:
2521	addql	#1,d0
2522	rts
2523
2524#ifdef FPCOPROC
2525/*
2526 * Save and restore 68881 state.
2527 * Pretty awful looking since our assembler does not
2528 * recognize FP mnemonics.
2529 */
2530ENTRY(m68881_save)
2531	movl	sp@(4),a0		| save area pointer
2532	fsave	a0@			| save state
2533	tstb	a0@			| null state frame?
2534	jeq	Lm68881sdone		| yes, all done
2535	fmovem fp0-fp7,a0@(216)		| save FP general registers
2536	fmovem fpcr/fpsr/fpi,a0@(312)	| save FP control registers
2537Lm68881sdone:
2538	rts
2539
2540ENTRY(m68881_restore)
2541	movl	sp@(4),a0		| save area pointer
2542	tstb	a0@			| null state frame?
2543	jeq	Lm68881rdone		| yes, easy
2544	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
2545	fmovem	a0@(216),fp0-fp7	| restore FP general registers
2546Lm68881rdone:
2547	frestore a0@			| restore state
2548	rts
2549#endif
2550
2551/*
2552 * Handle the nitty-gritty of rebooting the machine.
2553 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
2554 * Note that we must be running in an address range that is mapped one-to-one
2555 * logical to physical so that the PC is still valid immediately after the MMU
2556 * is turned off.  We have conveniently mapped the last page of physical
2557 * memory this way.
2558 */
2559	.globl	_doboot
2560_doboot:
2561	movl	#CACHE_OFF,d0
2562	movc	d0,cacr			| disable on-chip cache(s)
2563#if defined(HP320) || defined(HP350) || defined(HP370)
2564	tstl	_ectype
2565	jeq	Lnocache5
2566	MMUADDR(a0)
2567	andl	#~MMU_CEN,a0@(MMUCMD)	| disable external cache
2568Lnocache5:
2569#endif
2570	lea	MAXADDR,a0		| last page of physical memory
2571	movl	_boothowto,a0@+		| store howto
2572	movl	_bootdev,a0@+		| and devtype
2573	lea	Lbootcode,a1		| start of boot code
2574	lea	Lebootcode,a3		| end of boot code
2575Lbootcopy:
2576	movw	a1@+,a0@+		| copy a word
2577	cmpl	a3,a1			| done yet?
2578	jcs	Lbootcopy		| no, keep going
2579	jmp	MAXADDR+8		| jump to last page
2580
2581Lbootcode:
2582	lea	MAXADDR+0x800,sp	| physical SP in case of NMI
2583#if defined(HP330) || defined(HP360) || defined(HP370)
2584	tstl	_mmutype		| HP MMU?
2585	jeq	LhpmmuB			| yes, skip
2586	movl	#0,a0@			| value for pmove to TC (turn off MMU)
2587	pmove	a0@,tc			| disable MMU
2588	jmp	0x1A4			| goto REQ_REBOOT
2589LhpmmuB:
2590#endif
2591#if defined(HP320) || defined(HP350)
2592	MMUADDR(a0)
2593	movl	#0xFFFF0000,a0@(MMUCMD)	| totally disable MMU
2594	movl	d2,MAXADDR+NBPG-4	| restore old high page contents
2595	jmp	0x1A4			| goto REQ_REBOOT
2596#endif
2597Lebootcode:
2598
2599	.data
2600	.space	NBPG
2601tmpstk:
2602	.globl	_machineid
2603_machineid:
2604	.long	0		| default to 320
2605	.globl	_mmutype,_protorp
2606_mmutype:
2607	.long	0		| default to HP MMU
2608_protorp:
2609	.long	0,0		| prototype root pointer
2610	.globl	_ectype
2611_ectype:
2612	.long	0		| external cache type, default to none
2613	.globl	_internalhpib
2614_internalhpib:
2615	.long	1		| has internal HP-IB, default to yes
2616	.globl	_cold
2617_cold:
2618	.long	1		| cold start flag
2619	.globl	_intiobase, _intiolimit, _extiobase, _CLKbase, _MMUbase
2620	.globl	_proc0paddr
2621_proc0paddr:
2622	.long	0		| KVA of proc0 u-area
2623_intiobase:
2624	.long	0		| KVA of base of internal IO space
2625_intiolimit:
2626	.long	0		| KVA of end of internal IO space
2627_extiobase:
2628	.long	0		| KVA of base of external IO space
2629_CLKbase:
2630	.long	0		| KVA of base of clock registers
2631_MMUbase:
2632	.long	0		| KVA of base of HP MMU registers
2633#ifdef DEBUG
2634	.globl	fulltflush, fullcflush
2635fulltflush:
2636	.long	0
2637fullcflush:
2638	.long	0
2639	.globl	timebomb
2640timebomb:
2641	.long	0
2642#endif
2643/* interrupt counters */
2644	.globl	_intrcnt,_eintrcnt,_intrnames,_eintrnames
2645_intrnames:
2646	.asciz	"spur"
2647	.asciz	"hil"
2648	.asciz	"lev2"
2649	.asciz	"lev3"
2650	.asciz	"lev4"
2651	.asciz	"lev5"
2652	.asciz	"dma"
2653	.asciz	"clock"
2654#ifdef PROFTIMER
2655	.asciz  "pclock"
2656#endif
2657	.asciz	"nmi"
2658_eintrnames:
2659	.even
2660_intrcnt:
2661#ifdef PROFTIMER
2662	.long	0,0,0,0,0,0,0,0,0,0
2663#else
2664	.long	0,0,0,0,0,0,0,0,0
2665#endif
2666_eintrcnt:
2667