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