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